From fa55316272958325c194a6460e9a8494d94175e5 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 08:57:15 -0600 Subject: [PATCH 01/61] o added CMPL_CLASD definition to CONFIG.gnuCommon, CONFIG.solarisCommon.solarisCommon, configure/os/CONFIG.win32-x86.win32-x86 o added CMPLR_SRC_DIRS to ALL_SRC_DIRS, and added compiler/$CMPLR_CLASS) to INSTALL_INCLUDES in CONFIG_COMMON o added additional compiler specific rule deciding where things are installed to in CONFIG_COMMON o added compiler specific include install to RULES_BUILD o changed configure/os/CONFIG.linux-x86.linux-x86 to specify minimum arch is 586 (pentium circa 1995) o changed configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin to specify minimum arch is 586 (pentium circa 1995) o added epicsAtoimic facility to libCom/Makefile o added testing and performance measurement to libCom/test/Makefile --- configure/RULES_BUILD | 2 +- configure/os/CONFIG.win32-x86.win32-x86 | 2 +- src/libCom/osi/Makefile | 6 ++++++ src/libCom/test/Makefile | 9 +++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 9636d6e47..f4ea5009e 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -410,7 +410,7 @@ $(INSTALL_INCLUDE)/% : % $(INSTALL_INCLUDE)/os/$(OS_CLASS)/% : % $(ECHO) "Installing OS dependent include file $@" @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) - + $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS)/% : % $(ECHO) "Installing compiler dependent include file $@" @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86 index 86b9510ac..da07db685 100644 --- a/configure/os/CONFIG.win32-x86.win32-x86 +++ b/configure/os/CONFIG.win32-x86.win32-x86 @@ -124,7 +124,7 @@ OPT_CXXFLAGS_YES = /Ox /GL # /D_CRTDBG_MAP_ALLOC # /RTCsu catch bugs occurring only in optimized code # /DEPICS_FREELIST_DEBUG good for detecting mem mrg bugs -OPT_CXXFLAGS_NO = /RTCsu /Zi +OPT_CXXFLAGS_NO = /RTCsu /Zi # specify object file name and location OBJ_CXXFLAG = /Fo diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index 1f0ca4cdf..2b607de4b 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -44,6 +44,10 @@ INC += osiUnistd.h INC += osiWireFormat.h INC += osdWireFormat.h INC += osdWireConfig.h +INC += epicsAtomic.h +INC += epicsAtomicLocked.h +INC += epicsAtomicOSD.h +INC += epicsAtomicCD.h INC += epicsEndian.h INC += epicsReadline.h INC += epicsMessageQueue.h @@ -62,6 +66,8 @@ Com_SRCS += epicsEvent.cpp Com_SRCS += epicsTime.cpp Com_SRCS += epicsMessageQueue.cpp Com_SRCS += epicsMath.cpp +Com_SRCS += epicsAtomicLocked.cpp +Com_SRCS += epicsAtomicOSD.cpp Com_SRCS += epicsGeneralTime.c diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index 210cb7ec9..3c94f9850 100644 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -108,6 +108,11 @@ epicsMutexTest_SRCS += epicsMutexTest.cpp testHarness_SRCS += epicsMutexTest.cpp TESTS += epicsMutexTest +TESTPROD_HOST += epicsAtomicTest +epicsAtomicTest_SRCS += epicsAtomicTest.c +testHarness_SRCS += epicsAtomicTest.c +TESTS += epicsAtomicTest + TESTPROD_HOST += epicsExceptionTest epicsExceptionTest_SRCS += epicsExceptionTest.cpp testHarness_SRCS += epicsExceptionTest.cpp @@ -178,6 +183,10 @@ fdmgrTest_SRCS += fdmgrTest.c fdmgrTest_LIBS += ca # FIXME: program never exits. +TESTPROD_HOST += epicsAtomicPerform +epicsAtomicPerform_SRCS += epicsAtomicPerform.cpp +testHarness_SRCS += epicsAtomicPerform.cpp + TESTPROD_HOST += cvtFastPerform cvtFastPerform_SRCS += cvtFastPerform.cpp testHarness_SRCS += cvtFastPerform.cpp From ee2e367dad2c449ab91b7e2660b27b256ca6cd15 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 08:57:15 -0600 Subject: [PATCH 02/61] o added CMPL_CLASD definition to CONFIG.gnuCommon, CONFIG.solarisCommon.solarisCommon, configure/os/CONFIG.win32-x86.win32-x86 o added CMPLR_SRC_DIRS to ALL_SRC_DIRS, and added compiler/$CMPLR_CLASS) to INSTALL_INCLUDES in CONFIG_COMMON o added additional compiler specific rule deciding where things are installed to in CONFIG_COMMON o added compiler specific include install to RULES_BUILD o changed configure/os/CONFIG.linux-x86.linux-x86 to specify minimum arch is 586 (pentium circa 1995) o changed configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin to specify minimum arch is 586 (pentium circa 1995) o added epicsAtoimic facility to libCom/Makefile o added testing and performance measurement to libCom/test/Makefile --- configure/CONFIG.gnuCommon | 2 ++ configure/CONFIG_COMMON | 22 +++++++++++++++---- configure/RULES_BUILD | 4 ++++ configure/os/CONFIG.linux-x86.linux-x86 | 5 +++++ .../os/CONFIG.solarisCommon.solarisCommon | 2 ++ .../CONFIG.win32-x86-cygwin.win32-x86-cygwin | 5 +++++ .../os/CONFIG.win32-x86-mingw.win32-x86-mingw | 5 +++++ configure/os/CONFIG.win32-x86.win32-x86 | 4 +++- src/libCom/Makefile | 7 ++++++ src/libCom/test/Makefile | 9 ++++++++ 10 files changed, 60 insertions(+), 5 deletions(-) diff --git a/configure/CONFIG.gnuCommon b/configure/CONFIG.gnuCommon index f0548024e..94d1286e0 100644 --- a/configure/CONFIG.gnuCommon +++ b/configure/CONFIG.gnuCommon @@ -12,6 +12,8 @@ GNU = YES +CMPLR_CLASS = gcc + GNU_BIN = $(GNU_DIR)/bin GNU_LIB = $(GNU_DIR)/lib diff --git a/configure/CONFIG_COMMON b/configure/CONFIG_COMMON index 4bd8737f3..d142723a4 100644 --- a/configure/CONFIG_COMMON +++ b/configure/CONFIG_COMMON @@ -133,11 +133,14 @@ POSIX_YES = os/posix GENERIC_SRC_DIRS = .. $(SRC_DIRS) OS_SRC_DIRS += . $(foreach dir, .. $(SRC_DIRS), \ $(addprefix $(dir)/, os/$(OS_CLASS) $(POSIX_$(POSIX)) os/default )) -ALL_SRC_DIRS = $(OS_SRC_DIRS) $(GENERIC_SRC_DIRS) +CMPLR_SRC_DIRS += . $(foreach dir, .. $(SRC_DIRS), \ + $(addprefix $(dir)/, compiler/$(CMPLR_CLASS) compiler/default )) +ALL_SRC_DIRS = $(CMPLR_SRC_DIRS) $(OS_SRC_DIRS) $(GENERIC_SRC_DIRS) #-------------------------------------------------- # compile line include directories INSTALL_INCLUDES += \ + -I$(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS) \ -I$(INSTALL_INCLUDE)/os/$(OS_CLASS) \ -I$(INSTALL_INCLUDE) SRC_INCLUDES = -I$(COMMON_DIR) $(addprefix -I, $(wildcard $(ALL_SRC_DIRS))) @@ -379,24 +382,35 @@ INSTALL_PERMISSIONS = 444 # # auto determine the directory paths that things are installed to # RULES: -# 1) found in any one of several os specific area +# 0) found in any one of several compiler specific area +# => install to $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS) +# 1) not found in (0) and found in any one of several os specific area # => install to $(INSTALL_INCLUDE)/os/$(OS_CLASS) -# 2) not foundin (1) and found in generic area +# 2) not found in (1) and found in generic area # => install to $(INSTALL_INCLUDE) # 3) not found in (1) or (2) then may be (not yet) computer generated # => install into $(INSTALL_INCLUDE)/os/$(OS_CLASS) and let # build rules work on vpath # # These rules guarantee that the users include from -# no more than two directories +# no more than three directories # INSTALL_INC += $(foreach inc, $(INC), \ $(firstword \ + $(CMPLR_INSTALL_INC) \ $(OS_INSTALL_INC) \ $(GENERIC_INSTALL_INC) \ $(GENERATED_INSTALL_INC) ) ) INSTALL_INC += $(addprefix $(INSTALL_INCLUDE)/os/$(OS_CLASS)/, $(INC_$(OS_CLASS)) ) +# +# Rule 0 +# +CMPLR_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS)/, $(INSTALL_INC_jjj) ) +INSTALL_INC_jjj = $(foreach dir, $(CMPLR_SRC_DIRS), $(INSTALL_INC_iii) ) +INSTALL_INC_iii = $(subst $(dir)/, , $(INSTALL_INC_hhh) ) +INSTALL_INC_hhh = $(wildcard $(addsuffix /$(inc), $(dir)) ) + # # Rule 1 # diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index f7247a5be..54ddd9ac4 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -417,6 +417,10 @@ $(INSTALL_INCLUDE)/% : % $(INSTALL_INCLUDE)/os/$(OS_CLASS)/% : % $(ECHO) "Installing os dependent include file $@" @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) + +$(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS)/% : % + $(ECHO) "Installing compiler dependent include file $@" + @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) $(INSTALL_DOC)/%: % $(ECHO) "Installing doc $@" diff --git a/configure/os/CONFIG.linux-x86.linux-x86 b/configure/os/CONFIG.linux-x86.linux-x86 index 6414b5ab0..775680e11 100644 --- a/configure/os/CONFIG.linux-x86.linux-x86 +++ b/configure/os/CONFIG.linux-x86.linux-x86 @@ -16,3 +16,8 @@ STATIC_LDLIBS_NO= SHRLIB_LDFLAGS += -Wl,-h$@ LOADABLE_SHRLIB_LDFLAGS += -Wl,-h$@ + +# this means that atomic instrnsics are available, but that +# users with 486 processors and earlier will need specialized +# configure files +ARCH_DEP_CFLAGS += -march=i586 \ No newline at end of file diff --git a/configure/os/CONFIG.solarisCommon.solarisCommon b/configure/os/CONFIG.solarisCommon.solarisCommon index c38fc92d8..117957575 100644 --- a/configure/os/CONFIG.solarisCommon.solarisCommon +++ b/configure/os/CONFIG.solarisCommon.solarisCommon @@ -7,6 +7,8 @@ # Sites may override these definitions in CONFIG_SITE.solaris-sparc.solaris-sparc #------------------------------------------------------- +CMPLR_CLASS = solStudio + SPARCWORKS = /opt/SUNWspro GNU = NO diff --git a/configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin b/configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin index aa29f4d7a..5dca1b714 100644 --- a/configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin +++ b/configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin @@ -23,6 +23,11 @@ SHRLIB_CFLAGS = SHRLIB_LDFLAGS = -shared -Wl,--out-implib,$(LIB_PREFIX)$*$(LIB_SUFFIX) LOADABLE_SHRLIB_LDFLAGS = -shared -Wl,--out-implib,$(LIB_PREFIX)$*$(LIB_SUFFIX) +# this means that atomic instrnsics are available, but that +# users with 486 processors and earlier will need specialized +# configure files +ARCH_DEP_CFLAGS += -march=i586 + # Override linking with gcc library from CONFIG.gnuCommon GNU_LDLIBS_YES = diff --git a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw index 8309f8b45..32a6733ad 100644 --- a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw @@ -18,6 +18,11 @@ RANLIB = ranlib RES=.coff RCCMD = windres $(INCLUDES) $< $@ +# this means that atomic instrnsics are available, but that +# users with 486 processors and earlier will need specialized +# configure files +ARCH_DEP_CFLAGS += -march=i586 + # No -fPIC avoids "-fPIC ignored for target (all code is position independent)" SHRLIB_CFLAGS = SHRLIB_LDFLAGS = -shared -Wl,--out-implib,$(LIB_PREFIX)$*$(LIB_SUFFIX) diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86 index 4f55f943d..29b27cf42 100644 --- a/configure/os/CONFIG.win32-x86.win32-x86 +++ b/configure/os/CONFIG.win32-x86.win32-x86 @@ -11,6 +11,8 @@ VALID_BUILDS = Host Ioc +CMPLR_CLASS = msvc + # convert UNIX path to native path PATH_FILTER = $(subst /,\\,$(1)) @@ -120,7 +122,7 @@ OPT_CXXFLAGS_YES = /Ox /GL # /D_CRTDBG_MAP_ALLOC # /RTCsu catch bugs occurring only in optimized code # /DEPICS_FREELIST_DEBUG good for detecting mem mrg bugs -OPT_CXXFLAGS_NO = /RTCsu /Zi +OPT_CXXFLAGS_NO = /RTCsu /Zi # specify object file name and location OBJ_CXXFLAG = /Fo diff --git a/src/libCom/Makefile b/src/libCom/Makefile index 57c2f7ab0..02efe9348 100644 --- a/src/libCom/Makefile +++ b/src/libCom/Makefile @@ -184,6 +184,10 @@ INC += osiUnistd.h INC += osiWireFormat.h INC += osdWireFormat.h INC += osdWireConfig.h +INC += epicsAtomic.h +INC += epicsAtomicLocked.h +INC += epicsAtomicOSD.h +INC += epicsAtomicCD.h INC += epicsEndian.h INC += epicsReadline.h INC += epicsMessageQueue.h @@ -202,6 +206,8 @@ SRCS += epicsEvent.cpp SRCS += epicsTime.cpp SRCS += epicsMessageQueue.cpp SRCS += epicsMath.cpp +SRCS += epicsAtomicLocked.cpp +SRCS += epicsAtomicOSD.cpp SRCS += epicsGeneralTime.c SRCS += osiClockTime.c @@ -222,6 +228,7 @@ SRCS += epicsTempFile.cpp SRCS += epicsStdio.c SRCS += osdStdio.c + osdEnv_CFLAGS_WIN32= -U__STDC__ SRCS += osdThread.c diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index 9bf92f528..07a4276c0 100644 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -107,6 +107,11 @@ epicsMutexTest_SRCS += epicsMutexTest.cpp testHarness_SRCS += epicsMutexTest.cpp TESTS += epicsMutexTest +TESTPROD_HOST += epicsAtomicTest +epicsAtomicTest_SRCS += epicsAtomicTest.c +testHarness_SRCS += epicsAtomicTest.c +TESTS += epicsAtomicTest + TESTPROD_HOST += epicsExceptionTest epicsExceptionTest_SRCS += epicsExceptionTest.cpp testHarness_SRCS += epicsExceptionTest.cpp @@ -177,6 +182,10 @@ fdmgrTest_SRCS += fdmgrTest.c fdmgrTest_LIBS += ca # FIXME: program never exits. +TESTPROD_HOST += epicsAtomicPerform +epicsAtomicPerform_SRCS += epicsAtomicPerform.cpp +testHarness_SRCS += epicsAtomicPerform.cpp + TESTPROD_HOST += cvtFastPerform cvtFastPerform_SRCS += cvtFastPerform.cpp testHarness_SRCS += cvtFastPerform.cpp From 747a59fd7fe51393a5033c3eb0ebaca57105dad0 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 09:13:38 -0600 Subject: [PATCH 03/61] o added epicsAtomic implementation including compiler and os specific files o added functionality and performance testing --- src/libCom/osi/compiler/clang/epicsAtomicCD.h | 27 + .../osi/compiler/default/epicsAtomicCD.h | 25 + src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 97 ++++ src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 165 ++++++ .../osi/compiler/solStudio/epicsAtomicCD.h | 27 + src/libCom/osi/epicsAtomic.h | 99 ++++ src/libCom/osi/epicsAtomicLocked.cpp | 103 ++++ src/libCom/osi/epicsAtomicLocked.h | 72 +++ src/libCom/osi/epicsAtomicOSD.cpp | 45 ++ src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 130 +++++ src/libCom/osi/os/default/epicsAtomicOSD.h | 21 + src/libCom/osi/os/solaris/epicsAtomicOSD.h | 105 ++++ src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 211 ++++++++ src/libCom/test/epicsAtomicPerform.cpp | 499 ++++++++++++++++++ src/libCom/test/epicsAtomicTest.c | 117 ++++ 15 files changed, 1743 insertions(+) create mode 100644 src/libCom/osi/compiler/clang/epicsAtomicCD.h create mode 100644 src/libCom/osi/compiler/default/epicsAtomicCD.h create mode 100644 src/libCom/osi/compiler/gcc/epicsAtomicCD.h create mode 100644 src/libCom/osi/compiler/msvc/epicsAtomicCD.h create mode 100644 src/libCom/osi/compiler/solStudio/epicsAtomicCD.h create mode 100644 src/libCom/osi/epicsAtomic.h create mode 100644 src/libCom/osi/epicsAtomicLocked.cpp create mode 100644 src/libCom/osi/epicsAtomicLocked.h create mode 100644 src/libCom/osi/epicsAtomicOSD.cpp create mode 100644 src/libCom/osi/os/WIN32/epicsAtomicOSD.h create mode 100644 src/libCom/osi/os/default/epicsAtomicOSD.h create mode 100644 src/libCom/osi/os/solaris/epicsAtomicOSD.h create mode 100644 src/libCom/osi/os/vxWorks/epicsAtomicOSD.h create mode 100644 src/libCom/test/epicsAtomicPerform.cpp create mode 100644 src/libCom/test/epicsAtomicTest.c diff --git a/src/libCom/osi/compiler/clang/epicsAtomicCD.h b/src/libCom/osi/compiler/clang/epicsAtomicCD.h new file mode 100644 index 000000000..ecb3833d1 --- /dev/null +++ b/src/libCom/osi/compiler/clang/epicsAtomicCD.h @@ -0,0 +1,27 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef cdAtomic_h +#define cdAtomic_h + +#if defined ( __cplusplus ) +# define OSD_ATOMIC_INLINE inline +#else +# define OSD_ATOMIC_INLINE __inline__ +#endif + +#include "osdAtomic.h" + +#endif /* cdAtomic_h */ diff --git a/src/libCom/osi/compiler/default/epicsAtomicCD.h b/src/libCom/osi/compiler/default/epicsAtomicCD.h new file mode 100644 index 000000000..a4edb81c9 --- /dev/null +++ b/src/libCom/osi/compiler/default/epicsAtomicCD.h @@ -0,0 +1,25 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef cdAtomic_h +#define cdAtomic_h + +#if __STDC_VERSION__ >= 199901L || defined ( __cplusplus ) +# define OSD_ATOMIC_INLINE inline +#endif + +#include "osdAtomic.h" + +#endif /* cdAtomic_h */ diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h new file mode 100644 index 000000000..364a86e0d --- /dev/null +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -0,0 +1,97 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef cdAtomic_h +#define cdAtomic_h + +#ifndef __GNUC__ +# error this header is only for use with the gnu compiler +#endif + +#define OSD_ATOMIC_INLINE __inline__ + +#define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B) +#define GCC_ATOMIC_CONCATR( A, B ) A ## B + +#define GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ + GCC_ATOMIC_CONCAT ( \ + __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \ + __SIZEOF_INT__ ) + +#define GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \ + GCC_ATOMIC_CONCAT ( \ + __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \ + __SIZEOF_SIZE_T__ ) + +#if GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ + && defined GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T + +#define OSD_ATOMIC_GCC + +#ifdef __cplusplus +extern "C" { +#endif + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return __sync_add_and_fetch ( pTarget, 1u ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return __sync_sub_and_fetch ( pTarget, 1u ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, + size_t newValue ) +{ + *pTarget = newValue; + __sync_synchronize (); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, + unsigned newValue ) +{ + *pTarget = newValue; + __sync_synchronize (); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + __sync_synchronize (); + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + const size_t prev = __sync_lock_test_and_set ( pTarget, 1u ); + return prev == 0; +} + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#else /* if GCC_ATOMIC_INTRINSICS_AVAIL */ + + /* + * not available as gcc intrinsics so we + * will employ an os specific inline solution + */ +# include "osdAtomic.h" + +#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL */ + +#endif /* cdAtomic_h */ diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h new file mode 100644 index 000000000..1353d121e --- /dev/null +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -0,0 +1,165 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef cdAtomic_h +#define cdAtomic_h + +#include "epicsAssert.h" + +#ifndef _MSC_VER +# error this header file is only for use with with the Microsoft Compiler +#endif + +#ifdef _MSC_EXTENSIONS + +/* + * I have discovered an anomaly in visual c++ where + * the DLL instantiation of an exported inline interface + * does not occur in a c++ code unless "inline" is used. + */ +#if defined ( __cplusplus ) +# define OSD_ATOMIC_INLINE inline +#elif defined ( _MSC_VER ) +# define OSD_ATOMIC_INLINE __inline +#endif + +#if defined ( _M_X64 ) || defined ( _M_IA64 ) +# define OSD_ATOMIC_64 +#endif /* defined ( _M_X64 ) || defined ( _M_IA64 ) */ + +#include + +#pragma intrinsic ( _InterlockedExchange ) +#pragma intrinsic ( _InterlockedCompareExchange ) +#pragma intrinsic ( _InterlockedIncrement ) +#pragma intrinsic ( _InterlockedDecrement ) +#pragma intrinsic ( _InterlockedExchange ) +#pragma intrinsic ( _InterlockedExchangeAdd ) +#if OSD_ATOMIC_64 +# pragma intrinsic ( _InterlockedIncrement64 ) +# pragma intrinsic ( _InterlockedDecrement64 ) +# pragma intrinsic ( _InterlockedExchange64 ) +# pragma intrinsic ( _InterlockedExchangeAdd64 ) +#endif + +/* + * The windows doc appears to recommend defining InterlockedExchange + * to be _InterlockedExchange to cause it to be an intrinsic, but that + * creates issues when later, in a windows os specific header, we include + * windows.h so we except some code duplication between the msvc csAtomic.h + * and win32 osdAtomic.h to avoid problems, and to keep the os specific + * windows.h header file out of the msvc cdAtomic.h + */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* necessary for next two functions */ +STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) ); + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + long * const pTarg = ( long * ) ( pTarget ); + _InterlockedExchange ( pTarg, ( long ) newVal ); +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + long * const pTarg = ( long * ) ( pTarget ); + return _InterlockedCompareExchange ( pTarg, 1, 0 ) == 0; +} + + +#if ! OSD_ATOMIC_64 + +/* + * necessary for next four functions + * + * looking at the MS documentation it appears that they will + * keep type long the same size as an int on 64 bit builds + */ +STATIC_ASSERT ( sizeof ( long ) == sizeof ( size_t ) ); + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + long * const pTarg = ( long * ) pTarget; + return _InterlockedIncrement ( pTarg ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + long * const pTarg = ( long * ) ( pTarget ); + return _InterlockedDecrement ( pTarg ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + long * const pTarg = ( long * ) ( pTarget ); + _InterlockedExchange ( pTarg, ( long ) newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + long * const pTarg = ( long * ) ( pTarget ); + return _InterlockedExchangeAdd ( pTarg, 0 ); +} + +#else /* ! OSD_ATOMIC_64 */ + +/* + * necessary for next four functions + */ +STATIC_ASSERT ( sizeof ( long long ) == sizeof ( size_t ) ); + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + long long * const pTarg = ( long long * ) pTarget; + return _InterlockedIncrement64 ( pTarg ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + long long * const pTarg = ( long long * ) ( pTarget ); + return _InterlockedDecrement64 ( pTarg ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + long long * const pTarg = ( long long * ) ( pTarget ); + _InterlockedExchange64 ( pTarg, ( long long ) newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + long long * const pTarg = ( long long * ) ( pTarget ); + return _InterlockedExchangeAdd64 ( pTarg, 0 ); +} + +#endif /* ! OSD_ATOMIC_64 */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#else /* ifdef _MSC_EXTENSIONS */ + +#if defined ( __cplusplus ) +# define OSD_ATOMIC_INLINE inline +# include "osdAtomic.h" +#endif + +#endif /* ifdef _MSC_EXTENSIONS */ + +#endif /* cdAtomic_h */ diff --git a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h new file mode 100644 index 000000000..a69bb19bb --- /dev/null +++ b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h @@ -0,0 +1,27 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef cdAtomic_h +#define cdAtomic_h + +#if defined ( __cplusplus ) +# define OSD_ATOMIC_INLINE inline +#else +# define OSD_ATOMIC_INLINE __inline +#endif + +#include "osdAtomic.h" + +#endif /* cdAtomic_h */ diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h new file mode 100644 index 000000000..c94c2de1e --- /dev/null +++ b/src/libCom/osi/epicsAtomic.h @@ -0,0 +1,99 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomic_h +#define epicsAtomic_h + +#include /* define size_t */ + +#include "shareLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * lock out other smp processors from accessing the target, + * sync target in cache, add one to target, flush target in + * cache, allow other smp processors to access the target, + * return new value of target as modified by this operation + * + * increment is chosen as the primitive here because, + * compared to add, it is more likely to be implemented + * atomically on old architectures such as 68k + */ +epicsShareFunc size_t epicsAtomicIncrSizeT ( size_t * pTarget ); + +/* + * lock out other smp processors from accessing the target, + * sync target in cache, subtract one from target, flush target + * in cache, allow out other smp processors to access the target, + * return new value of target as modified by this operation + * + * decrement is chosen as the primitive here because, + * compared to subtract, it is more likely to be implemented + * atomically on old architectures such as 68k + */ +epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget ); + +/* + * set target in cache, flush target in cache + */ +epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue ); +epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue ); + +/* + * fetch target in cache, return new value of target + */ +epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget ); + +/* + * lock out other smp processors from accessing the target, + * sync target in cache, if target is zero set target to + * non-zero (true) value, flush target in cache, allow out + * other smp processors to access the target, return true if + * this request changed the target from a zero value to a + * non-zero (true) value and otherwise false + * + * test and set is chosen as the primitive here because, + * compared to comapare-and-swap it is more likely to + * be implemented atomically on old architectures such as 68k + */ +epicsShareFunc unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ); + +/* + * the following are, never inline and always synchronized by a global + * mutual exclusion lock, implementations of the epicsAtomicXxxx interface + * which may used to implement the epicsAtomicXxxx functions when + * more efficent primitives aren't available + */ +epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget ); +epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); +epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); +epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); +epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); +epicsShareFunc unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +/* + * options for inline compiler instrinsic or os specific + * implementations of the above function prototypes + */ +#include "epicsAtomicCD.h" + +#endif /* epicsAtomic_h */ diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp new file mode 100644 index 000000000..b9ea22757 --- /dev/null +++ b/src/libCom/osi/epicsAtomicLocked.cpp @@ -0,0 +1,103 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + * + * Provide a global mutex version of the atomic functions for when + * we dont have more efficent OS primitives or compiler intriniscs + * to use instead. + * + * We implement these mutex-based primitives upon the libCom private + * interface epicsMutexOsdXxxx because, in libCom, it is convenient + * to make this a standalone primitive upon which we can implement + * epicsMutex. + */ + +#define epicsExportSharedSymbols +#include "epicsAtomic.h" +#include "epicsMutex.h" + +namespace { + +class AtomicGuard { +public: + AtomicGuard (); + ~AtomicGuard (); +private: + static epicsMutexOSD & m_mutex; +}; + +// +// see c++ FAQ, static init order fiasco +// +epicsMutexOSD & AtomicGuard :: m_mutex = * epicsMutexOsdCreate (); + +inline AtomicGuard :: AtomicGuard () +{ + const int status = epicsMutexOsdLock ( & m_mutex ); + assert ( status == epicsMutexLockOK ); +} + +inline AtomicGuard :: ~AtomicGuard () +{ + epicsMutexOsdUnlock ( & m_mutex ); +} + +} // end of anonymous namespace + +extern "C" { + +size_t epicsLockedIncrSizeT ( size_t * pTarget ) +{ + AtomicGuard atomicGuard; + return ++(*pTarget); +} + +size_t epicsLockedDecrSizeT ( size_t * pTarget ) +{ + AtomicGuard atomicGuard; + return --(*pTarget); +} + +void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ) +{ + AtomicGuard atomicGuard; + *pTarget = newVal; +} + +void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + AtomicGuard atomicGuard; + *pTarget = newVal; +} + +size_t epicsLockedGetSizeT ( const size_t * pTarget ) +{ + AtomicGuard atomicGuard; + return *pTarget; +} + +unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ) +{ + AtomicGuard atomicGuard; + const bool weWillSetIt = ( *pTarget == 0u ); + if ( weWillSetIt ) { + *pTarget = 1u; + } + return weWillSetIt; +} + +} // end of extern "C" + + + + diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h new file mode 100644 index 000000000..0aec9c8b5 --- /dev/null +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -0,0 +1,72 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomicLocked_h +#define epicsAtomicLocked_h + +#if defined ( OSD_ATOMIC_INLINE ) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + return epicsLockedTestAndSetUIntT ( pTarget ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + epicsLockedSetUIntT ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return epicsLockedIncrSizeT ( pTarget ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return epicsLockedDecrSizeT ( pTarget ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + epicsLockedSetSizeT ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + return epicsLockedGetSizeT ( pTarget ); +} + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#else /* if defined ( OSD_ATOMIC_INLINE ) */ + +# define epicsAtomicIncrSizeT epicsLockedIncrSizeT +# define epicsAtomicDecrSizeT epicsLockedDecrSizeT +# define epicsAtomicSetSizeT epicsLockedSetSizeT +# define epicsAtomicSetUIntT epicsLockedSetUIntT +# define epicsAtomicGetSizeT epicsLockedGetSizeT +# define epicsAtomicTestAndSetUIntT epicsLockedTestAndSetUIntT + +#endif /* if defined ( OSD_ATOMIC_INLINE ) */ + +#endif /* epicsAtomicLocked_h */ + + diff --git a/src/libCom/osi/epicsAtomicOSD.cpp b/src/libCom/osi/epicsAtomicOSD.cpp new file mode 100644 index 000000000..a1b2ff4f5 --- /dev/null +++ b/src/libCom/osi/epicsAtomicOSD.cpp @@ -0,0 +1,45 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + + #include "epicsAtomic.h" + + /* + * OSD_ATOMIC_INLINE + * defined: define atomic functions in osdAtomic.h + * undefined: dont define atomic functions in osdAtomic.h + * + * OSD_ATOMIC_INLINE is typically set by the compiler specific file cdAtomic.h + * + * when we discover here that there is no implementation, and we guess that + * there isnt an inline keyword in the compiler then we define OSD_ATOMIC_INLINE + * empty and include osdAtomic.h to force an out of line implementation + * + * My first inclination was to place only one file of this type under os/default, + * but then this source file always includes default/osdAtomic.h, which isnt correct + * if a more specific os/xxx/osdAtromic.h exists, and so rather than duplicate an + * identical file in all of the os directories (that will get rediculous if there + * is ever a posix interface for the atomics) I moved it here to the osi directory. + * Another option would be to not make tthe current location be the first search + * in the gnu make VPATH, but I am somewhat nervous about changing something that + * fundamental in the build system. + * + * this behavior will work most of the time by defualt but it can always be + * replaced by an os specific implementation, which might be required if + * some of the functions are inline and some are not + */ + #ifndef OSD_ATOMIC_INLINE + # include "osdAtomic.h" + #endif + diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h new file mode 100644 index 000000000..7ea6385d4 --- /dev/null +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -0,0 +1,130 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef osdAtomic_h +#define osdAtomic_h + +#if defined ( OSD_ATOMIC_INLINE ) + +#include + +#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ +#include + +#include "epicsAssert.h" + +#define STRICT +#define VC_EXTRALEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* necessary for next two functions */ +STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) ); + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + InterlockedExchange ( pTarg, ( LONG ) newVal ); +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + long * const pTarg = ( LONG * ) ( pTarget ); + return InterlockedCompareExchange ( pTarg, 1, 0 ) == 0; +} + +/* + * on win32 a LONG is 32 bits, but I am concerned that + * we shouldnt use LONG_MAX here because with certain + * compilers a long will be 64 bits wide + */ +#define WIN32_LONG_MAX 0xffffffff +#if SIZE_MAX == WIN32_LONG_MAX + +/* + * necessary for next four functions + * + * looking at the MS documentation it appears that they will + * keep type long the same size as an int on 64 bit builds + */ +STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( size_t ) ); + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + LONG * const pTarg = ( LONG * ) pTarget; + return InterlockedIncrement ( pTarg ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + return InterlockedDecrement ( pTarg ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + InterlockedExchange ( pTarg, ( LONG ) newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + return InterlockedExchangeAdd ( pTarg, 0 ); +} + +#else /* SIZE_MAX == WIN32_LONG_MAX */ + +/* + * necessary for next four functions + */ +STATIC_ASSERT ( sizeof ( LONGLONG ) == sizeof ( size_t ) ); + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + LONGLONG * const pTarg = ( LONGLONG * ) pTarget; + return InterlockedIncrement64 ( pTarg ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); + return InterlockedDecrement64 ( pTarg ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); + InterlockedExchange64 ( pTarg, ( LONGLONG ) newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); + return InterlockedExchangeAdd64 ( pTarg, 0 ); +} + +#endif /* SIZE_MAX == WIN32_LONG_MAX */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#endif /* if defined ( OSD_ATOMIC_INLINE ) */ + +#endif /* ifndef osdAtomic_h */ diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.h b/src/libCom/osi/os/default/epicsAtomicOSD.h new file mode 100644 index 000000000..f8033d9d5 --- /dev/null +++ b/src/libCom/osi/os/default/epicsAtomicOSD.h @@ -0,0 +1,21 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef osdAtomic +#define osdAtomic + +#include "epicsAtomicLocked.h" + +#endif /* osdAtomic */ diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h new file mode 100644 index 000000000..b2521848d --- /dev/null +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -0,0 +1,105 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef osdAtomic_h +#define osdAtomic_h + +#if defined ( OSD_ATOMIC_INLINE ) + +/* + * atomic.h exists only in Solaris 10 or higher + */ +#if defined ( __SunOS_5_10 ) + +#include +#include + +#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + const uchar_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u ); + return oldVal == 0u; +} + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + atomic_swap_uint ( pTarget, newVal ); +} + +#if SIZE_MAX == UINT_MAX + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return atomic_inc_uint_nv ( pTarget ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return atomic_dec_uint_nv ( pTarget ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + atomic_swap_uint ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + return atomic_or_uint_nv ( pTarget, 0U ); +} + +#else /* SIZE_MAX == UINT_MAX */ + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return atomic_inc_ulong_nv ( pTarget ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return atomic_dec_ulong_nv ( pTarget ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + atomic_swap_ulong ( pTarget, newval ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + return atomic_or_ulong_nv ( pTarget, 0U ); +} + +#endif /* SIZE_MAX == UINT_MAX */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#else /* ifdef __SunOS_5_10 */ + +#include "epicsAtomicLocked.h" + +#endif /* ifdef __SunOS_5_10 */ + +#endif /* if defined ( OSD_ATOMIC_INLINE ) */ + +#endif /* osdAtomic_h */ diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h new file mode 100644 index 000000000..8b8abd900 --- /dev/null +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -0,0 +1,211 @@ +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne, LLC, as Operator of +* Argonne National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef osdAtomic_h +#define osdAtomic_h + +#if defined ( OSD_ATOMIC_INLINE ) + +#include "vxWorks.h" /* obtain the version of vxWorks */ + +/* + * With vxWorks 6.6 and later we need to use vxAtomicLib + * to implement this functionality correctly on SMP systems + */ +#if _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 + +#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ +#include + +#include +#include +#include "epicsAssert.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * we make the probably correct guess that if SIZE_MAX + * is the same as UINT_MAX then sizeof ( atomic_t ) + * will be the same as sizeof ( size_t ) + * + * if SIZE_MAX != UINT_MAX then its 64 bit vxWorks and + * WRS doesnt not supply at this time the atomic interface + * for 8 byte integers that is needed - so that architecture + * receives the lock synchronized version + */ +#if SIZE_MAX == UINT_MAX + +STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) ); + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + /* + * vxAtomicLib doc indicates that vxAtomicInc is + * implemented using unsigned arithmetic + */ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + const atomic_t oldVal = vxAtomicInc ( pTarg ) + 1; + return ( ( size_t ) ( oldVal ) ) + 1u; +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + /* + * vxAtomicLib doc indicates that vxAtomicDec is + * implemented using unsigned arithmetic + */ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + const atomic_t oldVal = vxAtomicDec ( pTarg ) - 1; + return ( ( size_t ) ( oldVal ) ) - 1u; +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + vxAtomicSet ( pTarg, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return ( size_t ) vxAtomicGet ( pTarg ); +} + +#else /* SIZE_MAX == UINT_MAX */ + +/* + * if its 64 bit vxWorks and the compiler doesnt + * have an intrinsic then maybe there isnt any way to + * implement these without using a global lock because + * size_t is bigger than atomic_t + */ +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return epicsLockedIncrSizeT ( pTarget ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return epicsLockedDecrSizeT ( pTarget ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + epicsLockedSetSizeT ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + return epicsLockedGetSizeT ( pTarget ); +} + +#endif /* SIZE_MAX == UINT_MAX */ + +STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + vxAtomicSet ( pTarg, newVal ); +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return vxCas ( pTarget, 0, 1 ) != 0; +} + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#else /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */ + +#include "intLib.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + /* + * no need for memory barrior since this + * is a single cpu system. + */ + const int key = intLock (); + const size_t result = ++(*pTarget); + intUnlock ( key ); + return result; +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + const int key = intLock (); + const size_t result = --(*pTarget); + intUnlock ( key ); + return result; +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + *pTarget = newVal; +} + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + *pTarget = newVal; +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); + int * const pTarg = ( int * ) ( pTarget ); + const BOOL weSetIt = vxTas ( pTarg, 0, 1 ); + return weSetIt != 0; +} + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#endif /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */ + +#endif /* if defined ( OSD_ATOMIC_INLINE ) */ + +#endif /* osdAtomic_h */ diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp new file mode 100644 index 000000000..464c20afe --- /dev/null +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -0,0 +1,499 @@ + +#include +#include + +#include "epicsInterrupt.h" +#include "epicsAtomic.h" +#include "epicsTime.h" +#include "epicsUnitTest.h" +#include "testMain.h" + +using std :: size_t; + +class RefCtr { +public: + RefCtr (); + ~RefCtr (); + void reference (); + void unreference (); +private: + size_t m_cnt; +}; + +class Ownership { +public: + Ownership (); + Ownership ( RefCtr & refCtr ); + Ownership ( const Ownership & ); + ~Ownership (); + Ownership & operator = ( const Ownership & ); +private: + RefCtr * _pRefCtr; + static RefCtr m_noOwnership; +}; + +inline RefCtr :: RefCtr () +{ + epicsAtomicSetSizeT ( & m_cnt, 0 ); +} + +inline RefCtr :: ~RefCtr () +{ + unsigned cnt = epicsAtomicGetSizeT ( & m_cnt ); + assert ( cnt == 0u ); +} + +inline void RefCtr :: reference () +{ + epicsAtomicIncrSizeT ( & m_cnt ); +} + +inline void RefCtr :: unreference () +{ + epicsAtomicDecrSizeT ( & m_cnt ); +} + +RefCtr Ownership :: m_noOwnership; + +inline Ownership :: Ownership () : + _pRefCtr ( & m_noOwnership ) +{ + m_noOwnership.reference (); +} + +inline Ownership :: Ownership ( RefCtr & refCtr ) : + _pRefCtr ( & refCtr ) +{ + refCtr.reference (); +} + +inline Ownership :: Ownership ( const Ownership & ownership ) : + _pRefCtr ( ownership._pRefCtr ) +{ + _pRefCtr->reference (); +} + +inline Ownership :: ~Ownership () +{ + _pRefCtr->unreference (); +} + +inline Ownership & Ownership :: + operator = ( const Ownership & ownership ) +{ + RefCtr * const pOldRefCtr = _pRefCtr; + _pRefCtr = ownership._pRefCtr; + _pRefCtr->reference (); + pOldRefCtr->unreference (); + return *this; +} + +inline Ownership retOwnership ( const Ownership & ownership ) +{ + return Ownership ( ownership ); +} + +inline Ownership recurRetOwner10 ( const Ownership & ownershipIn ) +{ + Ownership ownership = + retOwnership ( + retOwnership ( + retOwnership ( + retOwnership ( + retOwnership ( ownershipIn ) ) ) ) ); + return retOwnership ( + retOwnership ( + retOwnership ( + retOwnership ( + retOwnership ( ownership ) ) ) ) ); +} + +inline Ownership recurRetOwner100 ( const Ownership & ownershipIn ) +{ + Ownership ownership = + recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( ownershipIn ) ) ) ) ); + return recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( ownership ) ) ) ) ); +} + +inline Ownership recurRetOwner1000 ( const Ownership & ownershipIn ) +{ + Ownership ownership = + recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( ownershipIn ) ) ) ) ); + return recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( ownership ) ) ) ) ); +} + +inline void passRefOwnership ( const Ownership & ownershipIn, Ownership & ownershipOut ) +{ + ownershipOut = ownershipIn; +} + +inline void passRefOwnership10 ( const Ownership & ownershipIn, Ownership & ownershipOut ) +{ + Ownership ownershipTmp0; + passRefOwnership ( ownershipIn, ownershipTmp0 ); + Ownership ownershipTmp1; + passRefOwnership ( ownershipTmp0, ownershipTmp1 ); + Ownership ownershipTmp2; + passRefOwnership ( ownershipTmp1, ownershipTmp2 ); + Ownership ownershipTmp3; + passRefOwnership ( ownershipTmp2, ownershipTmp3 ); + Ownership ownershipTmp4; + passRefOwnership ( ownershipTmp3, ownershipTmp4 ); + Ownership ownershipTmp5; + passRefOwnership ( ownershipTmp4, ownershipTmp5 ); + Ownership ownershipTmp6; + passRefOwnership ( ownershipTmp5, ownershipTmp6 ); + Ownership ownershipTmp7; + passRefOwnership ( ownershipTmp6, ownershipTmp7 ); + Ownership ownershipTmp8; + passRefOwnership ( ownershipTmp7, ownershipTmp8 ); + passRefOwnership ( ownershipTmp8, ownershipOut ); +} + +inline void passRefOwnership100 ( const Ownership & ownershipIn, Ownership & ownershipOut ) +{ + Ownership ownershipTmp0; + passRefOwnership10 ( ownershipIn, ownershipTmp0 ); + Ownership ownershipTmp1; + passRefOwnership10 ( ownershipTmp0, ownershipTmp1 ); + Ownership ownershipTmp2; + passRefOwnership10 ( ownershipTmp1, ownershipTmp2 ); + Ownership ownershipTmp3; + passRefOwnership10 ( ownershipTmp2, ownershipTmp3 ); + Ownership ownershipTmp4; + passRefOwnership10 ( ownershipTmp3, ownershipTmp4 ); + Ownership ownershipTmp5; + passRefOwnership10 ( ownershipTmp4, ownershipTmp5 ); + Ownership ownershipTmp6; + passRefOwnership10 ( ownershipTmp5, ownershipTmp6 ); + Ownership ownershipTmp7; + passRefOwnership10 ( ownershipTmp6, ownershipTmp7 ); + Ownership ownershipTmp8; + passRefOwnership10 ( ownershipTmp7, ownershipTmp8 ); + passRefOwnership10 ( ownershipTmp8, ownershipOut ); +} + +inline void passRefOwnership1000 ( const Ownership & ownershipIn, Ownership & ownershipOut ) +{ + Ownership ownershipTmp0; + passRefOwnership100 ( ownershipIn, ownershipTmp0 ); + Ownership ownershipTmp1; + passRefOwnership100 ( ownershipTmp0, ownershipTmp1 ); + Ownership ownershipTmp2; + passRefOwnership100 ( ownershipTmp1, ownershipTmp2 ); + Ownership ownershipTmp3; + passRefOwnership100 ( ownershipTmp2, ownershipTmp3 ); + Ownership ownershipTmp4; + passRefOwnership100 ( ownershipTmp3, ownershipTmp4 ); + Ownership ownershipTmp5; + passRefOwnership100 ( ownershipTmp4, ownershipTmp5 ); + Ownership ownershipTmp6; + passRefOwnership100 ( ownershipTmp5, ownershipTmp6 ); + Ownership ownershipTmp7; + passRefOwnership100 ( ownershipTmp6, ownershipTmp7 ); + Ownership ownershipTmp8; + passRefOwnership100 ( ownershipTmp7, ownershipTmp8 ); + passRefOwnership100 ( ownershipTmp8, ownershipOut ); +} + +time_t extTime = 0; + +// tests the time it takes to perform a call to an external +// function and also increment an integer word. The +// epicsInterruptIsInterruptContext function is an +// out-of-line function implemented in a sharable library +// so hopefully it wont be optimized away. +inline void tenOrdinaryIncr ( size_t & target ) +{ + int result = 0; + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + target = static_cast < unsigned > ( result ); +} + +inline void oneHundredOrdinaryIncr ( size_t & target ) +{ + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); +} + +inline void oneThousandOrdinaryIncr ( size_t & target ) +{ + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); +} + +inline void tenAtomicIncr ( size_t & target ) +{ + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); +} + +inline void oneHundredAtomicIncr ( size_t & target ) +{ + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); +} + +inline void oneThousandAtomicIncr ( size_t & target ) +{ + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); +} + +inline void tenAtomicTestAndSet ( unsigned & target ) +{ + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); +} + +inline void oneHundredAtomicTestAndSet ( unsigned & target ) +{ + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); +} + +inline void oneThousandAtomicTestAndSet ( unsigned & target ) +{ + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); +} + +inline void tenAtomicSet ( size_t & target ) +{ + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); +} + +inline void oneHundredAtomicSet ( size_t & target ) +{ + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); +} + +inline void oneThousandAtomicSet ( size_t & target ) +{ + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); +} + +static const unsigned N = 10000; + +void ordinaryIncrPerformance () +{ + epicsTime begin = epicsTime::getCurrent (); + size_t target; + epicsAtomicSetSizeT ( & target, 0 ); + for ( unsigned i = 0; i < N; i++ ) { + oneThousandOrdinaryIncr ( target ); + } + double delay = epicsTime::getCurrent () - begin; + testOk1 ( target == 0u ); + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "raw incr and a NOOP function call takes %f microseconds", delay ); +} + +void epicsAtomicIncrPerformance () +{ + epicsTime begin = epicsTime::getCurrent (); + size_t target; + epicsAtomicSetSizeT ( & target, 0 ); + for ( unsigned i = 0; i < N; i++ ) { + oneThousandAtomicIncr ( target ); + } + double delay = epicsTime::getCurrent () - begin; + testOk1 ( target == N * 1000u ); + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "epicsAtomicIncr() takes %f microseconds", delay ); +} + +void atomicCompareAndSetPerformance () +{ + epicsTime begin = epicsTime::getCurrent (); + size_t target; + epicsAtomicSetSizeT ( & target, 0 ); + testOk1 ( ! target ); + for ( unsigned i = 0; i < N; i++ ) { + oneThousandAtomicTestAndSet ( target ); + } + double delay = epicsTime::getCurrent () - begin; + testOk1 ( target ); + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "epicsAtomicCompareAndSet() takes %f microseconds", delay ); +} + +void recursiveOwnershipRetPerformance () +{ + RefCtr refCtr; + epicsTime begin = epicsTime::getCurrent (); + for ( unsigned i = 0; i < N; i++ ) { + Ownership ownership ( refCtr ); + recurRetOwner1000 ( ownership ); + } + double delay = epicsTime::getCurrent () - begin; + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "retOwnership() takes %f microseconds", delay ); +} + +void ownershipPassRefPerformance () +{ + RefCtr refCtr; + epicsTime begin = epicsTime::getCurrent (); + for ( unsigned i = 0; i < N; i++ ) { + Ownership ownershipSrc ( refCtr ); + Ownership ownershipDest; + passRefOwnership1000 ( ownershipSrc, ownershipDest ); + } + double delay = epicsTime::getCurrent () - begin; + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "passRefOwnership() takes %f microseconds", delay ); +} + +void epicsAtomicSetPerformance () +{ + epicsTime begin = epicsTime::getCurrent (); + unsigned target; + for ( unsigned i = 0; i < N; i++ ) { + oneThousandAtomicSet ( target ); + } + double delay = epicsTime::getCurrent () - begin; + testOk1 ( target == 0u ); + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "epicsAtomicSet() takes %f microseconds", delay ); +} + +MAIN(osiAtomicTest) +{ + testPlan(5); + // + // The tests running here are measuring fast + // functions so they tend to be impacted + // by where the cache lines are wrt to the + // virtual pages perhaps + // + epicsAtomicSetPerformance (); + ordinaryIncrPerformance (); + epicsAtomicIncrPerformance (); + recursiveOwnershipRetPerformance (); + ownershipPassRefPerformance (); + atomicCompareAndSetPerformance (); + return testDone(); +} diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c new file mode 100644 index 000000000..552e38aa6 --- /dev/null +++ b/src/libCom/test/epicsAtomicTest.c @@ -0,0 +1,117 @@ + +#include +#include + +#include "epicsAtomic.h" +#include "epicsTime.h" +#include "epicsThread.h" +#include "epicsUnitTest.h" +#include "testMain.h" + +typedef struct TestDataIncrDecr { + size_t m_testValue; + size_t m_testIterations; +} TestDataIncrDecr; + +static void incr ( void *arg ) +{ + TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg; + epicsAtomicIncrSizeT ( & pTestData->m_testValue ); + epicsAtomicIncrSizeT ( & pTestData->m_testIterations ); +} + +static void decr ( void *arg ) +{ + TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg; + epicsAtomicDecrSizeT ( & pTestData->m_testValue ); + epicsAtomicIncrSizeT ( & pTestData->m_testIterations ); +} + +typedef struct TestDataTNS { + unsigned m_testValue; + size_t m_testIterationsSet; + size_t m_testIterationsNotSet; +} TestDataTNS; + +int isModulo ( size_t N, size_t n ) +{ + return ( n % N ) == 0u; +} + +static void tns ( void *arg ) +{ + TestDataTNS * const pTestData = (TestDataTNS *) arg; + /* + * intentionally waste cpu and maximize + * contention for the shared data + */ + epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); + while ( ! epicsAtomicTestAndSetUIntT ( & pTestData->m_testValue ) ) { + } + epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); + epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u ); + epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); +} + +MAIN(osiAtomicTest) +{ + static const size_t N = 1000; + const unsigned int stackSize = + epicsThreadGetStackSize ( epicsThreadStackSmall ); + + testPlan(8); + + { + size_t i; + TestDataIncrDecr testData = { 0, N };; + epicsAtomicSetSizeT ( & testData.m_testValue, N ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, + "set/get %u", testData.m_testValue ); + epicsAtomicSetSizeT ( & testData.m_testIterations, 0u ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 0u, + "set/get %u", testData.m_testIterations ); + for ( i = 0u; i < N; i++ ) { + epicsThreadCreate ( "incr", + 50, stackSize, incr, & testData ); + epicsThreadCreate ( "decr", + 50, stackSize, decr, & testData ); + } + while ( testData.m_testIterations < 2 * N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N, + "incr/decr iterations %u", + testData.m_testIterations ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, + "incr/decr final value %u", + testData.m_testValue ); + } + + { + size_t i; + TestDataTNS testData = { 1, N, N }; + epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, + "set/get %u", testData.m_testIterationsSet ); + epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, + "set/get %u", testData.m_testIterationsNotSet ); + for ( i = 0u; i < N; i++ ) { + epicsThreadCreate ( "tns", + 50, stackSize, tns, & testData ); + } + epicsAtomicSetUIntT ( & testData.m_testValue, 0u ); + while ( testData.m_testIterationsSet < N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, + "test and set iterations %u", + testData.m_testIterationsSet ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, + "test and set not-set tracking = %u", + testData.m_testIterationsNotSet ); + } + + return testDone(); +} + From 100c79b88b14248daf427bac3d64d302e61be1bd Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 09:13:38 -0600 Subject: [PATCH 04/61] o added epicsAtomic implementation including compiler and os specific files o added functionality and performance testing --- src/libCom/osi/compiler/clang/epicsAtomicCD.h | 27 + .../osi/compiler/default/epicsAtomicCD.h | 25 + src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 97 ++++ src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 165 ++++++ .../osi/compiler/solStudio/epicsAtomicCD.h | 27 + src/libCom/osi/epicsAtomic.h | 99 ++++ src/libCom/osi/epicsAtomicLocked.cpp | 103 ++++ src/libCom/osi/epicsAtomicLocked.h | 72 +++ src/libCom/osi/epicsAtomicOSD.cpp | 45 ++ src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 130 +++++ src/libCom/osi/os/default/epicsAtomicOSD.h | 21 + src/libCom/osi/os/solaris/epicsAtomicOSD.h | 105 ++++ src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 211 ++++++++ src/libCom/test/epicsAtomicPerform.cpp | 499 ++++++++++++++++++ src/libCom/test/epicsAtomicTest.c | 117 ++++ 15 files changed, 1743 insertions(+) create mode 100644 src/libCom/osi/compiler/clang/epicsAtomicCD.h create mode 100644 src/libCom/osi/compiler/default/epicsAtomicCD.h create mode 100644 src/libCom/osi/compiler/gcc/epicsAtomicCD.h create mode 100644 src/libCom/osi/compiler/msvc/epicsAtomicCD.h create mode 100644 src/libCom/osi/compiler/solStudio/epicsAtomicCD.h create mode 100644 src/libCom/osi/epicsAtomic.h create mode 100644 src/libCom/osi/epicsAtomicLocked.cpp create mode 100644 src/libCom/osi/epicsAtomicLocked.h create mode 100644 src/libCom/osi/epicsAtomicOSD.cpp create mode 100644 src/libCom/osi/os/WIN32/epicsAtomicOSD.h create mode 100644 src/libCom/osi/os/default/epicsAtomicOSD.h create mode 100644 src/libCom/osi/os/solaris/epicsAtomicOSD.h create mode 100644 src/libCom/osi/os/vxWorks/epicsAtomicOSD.h create mode 100644 src/libCom/test/epicsAtomicPerform.cpp create mode 100644 src/libCom/test/epicsAtomicTest.c diff --git a/src/libCom/osi/compiler/clang/epicsAtomicCD.h b/src/libCom/osi/compiler/clang/epicsAtomicCD.h new file mode 100644 index 000000000..ecb3833d1 --- /dev/null +++ b/src/libCom/osi/compiler/clang/epicsAtomicCD.h @@ -0,0 +1,27 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef cdAtomic_h +#define cdAtomic_h + +#if defined ( __cplusplus ) +# define OSD_ATOMIC_INLINE inline +#else +# define OSD_ATOMIC_INLINE __inline__ +#endif + +#include "osdAtomic.h" + +#endif /* cdAtomic_h */ diff --git a/src/libCom/osi/compiler/default/epicsAtomicCD.h b/src/libCom/osi/compiler/default/epicsAtomicCD.h new file mode 100644 index 000000000..a4edb81c9 --- /dev/null +++ b/src/libCom/osi/compiler/default/epicsAtomicCD.h @@ -0,0 +1,25 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef cdAtomic_h +#define cdAtomic_h + +#if __STDC_VERSION__ >= 199901L || defined ( __cplusplus ) +# define OSD_ATOMIC_INLINE inline +#endif + +#include "osdAtomic.h" + +#endif /* cdAtomic_h */ diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h new file mode 100644 index 000000000..364a86e0d --- /dev/null +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -0,0 +1,97 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef cdAtomic_h +#define cdAtomic_h + +#ifndef __GNUC__ +# error this header is only for use with the gnu compiler +#endif + +#define OSD_ATOMIC_INLINE __inline__ + +#define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B) +#define GCC_ATOMIC_CONCATR( A, B ) A ## B + +#define GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ + GCC_ATOMIC_CONCAT ( \ + __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \ + __SIZEOF_INT__ ) + +#define GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \ + GCC_ATOMIC_CONCAT ( \ + __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \ + __SIZEOF_SIZE_T__ ) + +#if GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ + && defined GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T + +#define OSD_ATOMIC_GCC + +#ifdef __cplusplus +extern "C" { +#endif + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return __sync_add_and_fetch ( pTarget, 1u ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return __sync_sub_and_fetch ( pTarget, 1u ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, + size_t newValue ) +{ + *pTarget = newValue; + __sync_synchronize (); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, + unsigned newValue ) +{ + *pTarget = newValue; + __sync_synchronize (); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + __sync_synchronize (); + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + const size_t prev = __sync_lock_test_and_set ( pTarget, 1u ); + return prev == 0; +} + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#else /* if GCC_ATOMIC_INTRINSICS_AVAIL */ + + /* + * not available as gcc intrinsics so we + * will employ an os specific inline solution + */ +# include "osdAtomic.h" + +#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL */ + +#endif /* cdAtomic_h */ diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h new file mode 100644 index 000000000..1353d121e --- /dev/null +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -0,0 +1,165 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef cdAtomic_h +#define cdAtomic_h + +#include "epicsAssert.h" + +#ifndef _MSC_VER +# error this header file is only for use with with the Microsoft Compiler +#endif + +#ifdef _MSC_EXTENSIONS + +/* + * I have discovered an anomaly in visual c++ where + * the DLL instantiation of an exported inline interface + * does not occur in a c++ code unless "inline" is used. + */ +#if defined ( __cplusplus ) +# define OSD_ATOMIC_INLINE inline +#elif defined ( _MSC_VER ) +# define OSD_ATOMIC_INLINE __inline +#endif + +#if defined ( _M_X64 ) || defined ( _M_IA64 ) +# define OSD_ATOMIC_64 +#endif /* defined ( _M_X64 ) || defined ( _M_IA64 ) */ + +#include + +#pragma intrinsic ( _InterlockedExchange ) +#pragma intrinsic ( _InterlockedCompareExchange ) +#pragma intrinsic ( _InterlockedIncrement ) +#pragma intrinsic ( _InterlockedDecrement ) +#pragma intrinsic ( _InterlockedExchange ) +#pragma intrinsic ( _InterlockedExchangeAdd ) +#if OSD_ATOMIC_64 +# pragma intrinsic ( _InterlockedIncrement64 ) +# pragma intrinsic ( _InterlockedDecrement64 ) +# pragma intrinsic ( _InterlockedExchange64 ) +# pragma intrinsic ( _InterlockedExchangeAdd64 ) +#endif + +/* + * The windows doc appears to recommend defining InterlockedExchange + * to be _InterlockedExchange to cause it to be an intrinsic, but that + * creates issues when later, in a windows os specific header, we include + * windows.h so we except some code duplication between the msvc csAtomic.h + * and win32 osdAtomic.h to avoid problems, and to keep the os specific + * windows.h header file out of the msvc cdAtomic.h + */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* necessary for next two functions */ +STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) ); + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + long * const pTarg = ( long * ) ( pTarget ); + _InterlockedExchange ( pTarg, ( long ) newVal ); +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + long * const pTarg = ( long * ) ( pTarget ); + return _InterlockedCompareExchange ( pTarg, 1, 0 ) == 0; +} + + +#if ! OSD_ATOMIC_64 + +/* + * necessary for next four functions + * + * looking at the MS documentation it appears that they will + * keep type long the same size as an int on 64 bit builds + */ +STATIC_ASSERT ( sizeof ( long ) == sizeof ( size_t ) ); + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + long * const pTarg = ( long * ) pTarget; + return _InterlockedIncrement ( pTarg ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + long * const pTarg = ( long * ) ( pTarget ); + return _InterlockedDecrement ( pTarg ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + long * const pTarg = ( long * ) ( pTarget ); + _InterlockedExchange ( pTarg, ( long ) newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + long * const pTarg = ( long * ) ( pTarget ); + return _InterlockedExchangeAdd ( pTarg, 0 ); +} + +#else /* ! OSD_ATOMIC_64 */ + +/* + * necessary for next four functions + */ +STATIC_ASSERT ( sizeof ( long long ) == sizeof ( size_t ) ); + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + long long * const pTarg = ( long long * ) pTarget; + return _InterlockedIncrement64 ( pTarg ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + long long * const pTarg = ( long long * ) ( pTarget ); + return _InterlockedDecrement64 ( pTarg ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + long long * const pTarg = ( long long * ) ( pTarget ); + _InterlockedExchange64 ( pTarg, ( long long ) newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + long long * const pTarg = ( long long * ) ( pTarget ); + return _InterlockedExchangeAdd64 ( pTarg, 0 ); +} + +#endif /* ! OSD_ATOMIC_64 */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#else /* ifdef _MSC_EXTENSIONS */ + +#if defined ( __cplusplus ) +# define OSD_ATOMIC_INLINE inline +# include "osdAtomic.h" +#endif + +#endif /* ifdef _MSC_EXTENSIONS */ + +#endif /* cdAtomic_h */ diff --git a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h new file mode 100644 index 000000000..a69bb19bb --- /dev/null +++ b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h @@ -0,0 +1,27 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef cdAtomic_h +#define cdAtomic_h + +#if defined ( __cplusplus ) +# define OSD_ATOMIC_INLINE inline +#else +# define OSD_ATOMIC_INLINE __inline +#endif + +#include "osdAtomic.h" + +#endif /* cdAtomic_h */ diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h new file mode 100644 index 000000000..c94c2de1e --- /dev/null +++ b/src/libCom/osi/epicsAtomic.h @@ -0,0 +1,99 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomic_h +#define epicsAtomic_h + +#include /* define size_t */ + +#include "shareLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * lock out other smp processors from accessing the target, + * sync target in cache, add one to target, flush target in + * cache, allow other smp processors to access the target, + * return new value of target as modified by this operation + * + * increment is chosen as the primitive here because, + * compared to add, it is more likely to be implemented + * atomically on old architectures such as 68k + */ +epicsShareFunc size_t epicsAtomicIncrSizeT ( size_t * pTarget ); + +/* + * lock out other smp processors from accessing the target, + * sync target in cache, subtract one from target, flush target + * in cache, allow out other smp processors to access the target, + * return new value of target as modified by this operation + * + * decrement is chosen as the primitive here because, + * compared to subtract, it is more likely to be implemented + * atomically on old architectures such as 68k + */ +epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget ); + +/* + * set target in cache, flush target in cache + */ +epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue ); +epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue ); + +/* + * fetch target in cache, return new value of target + */ +epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget ); + +/* + * lock out other smp processors from accessing the target, + * sync target in cache, if target is zero set target to + * non-zero (true) value, flush target in cache, allow out + * other smp processors to access the target, return true if + * this request changed the target from a zero value to a + * non-zero (true) value and otherwise false + * + * test and set is chosen as the primitive here because, + * compared to comapare-and-swap it is more likely to + * be implemented atomically on old architectures such as 68k + */ +epicsShareFunc unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ); + +/* + * the following are, never inline and always synchronized by a global + * mutual exclusion lock, implementations of the epicsAtomicXxxx interface + * which may used to implement the epicsAtomicXxxx functions when + * more efficent primitives aren't available + */ +epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget ); +epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); +epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); +epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); +epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); +epicsShareFunc unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +/* + * options for inline compiler instrinsic or os specific + * implementations of the above function prototypes + */ +#include "epicsAtomicCD.h" + +#endif /* epicsAtomic_h */ diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp new file mode 100644 index 000000000..b9ea22757 --- /dev/null +++ b/src/libCom/osi/epicsAtomicLocked.cpp @@ -0,0 +1,103 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + * + * Provide a global mutex version of the atomic functions for when + * we dont have more efficent OS primitives or compiler intriniscs + * to use instead. + * + * We implement these mutex-based primitives upon the libCom private + * interface epicsMutexOsdXxxx because, in libCom, it is convenient + * to make this a standalone primitive upon which we can implement + * epicsMutex. + */ + +#define epicsExportSharedSymbols +#include "epicsAtomic.h" +#include "epicsMutex.h" + +namespace { + +class AtomicGuard { +public: + AtomicGuard (); + ~AtomicGuard (); +private: + static epicsMutexOSD & m_mutex; +}; + +// +// see c++ FAQ, static init order fiasco +// +epicsMutexOSD & AtomicGuard :: m_mutex = * epicsMutexOsdCreate (); + +inline AtomicGuard :: AtomicGuard () +{ + const int status = epicsMutexOsdLock ( & m_mutex ); + assert ( status == epicsMutexLockOK ); +} + +inline AtomicGuard :: ~AtomicGuard () +{ + epicsMutexOsdUnlock ( & m_mutex ); +} + +} // end of anonymous namespace + +extern "C" { + +size_t epicsLockedIncrSizeT ( size_t * pTarget ) +{ + AtomicGuard atomicGuard; + return ++(*pTarget); +} + +size_t epicsLockedDecrSizeT ( size_t * pTarget ) +{ + AtomicGuard atomicGuard; + return --(*pTarget); +} + +void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ) +{ + AtomicGuard atomicGuard; + *pTarget = newVal; +} + +void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + AtomicGuard atomicGuard; + *pTarget = newVal; +} + +size_t epicsLockedGetSizeT ( const size_t * pTarget ) +{ + AtomicGuard atomicGuard; + return *pTarget; +} + +unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ) +{ + AtomicGuard atomicGuard; + const bool weWillSetIt = ( *pTarget == 0u ); + if ( weWillSetIt ) { + *pTarget = 1u; + } + return weWillSetIt; +} + +} // end of extern "C" + + + + diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h new file mode 100644 index 000000000..0aec9c8b5 --- /dev/null +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -0,0 +1,72 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomicLocked_h +#define epicsAtomicLocked_h + +#if defined ( OSD_ATOMIC_INLINE ) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + return epicsLockedTestAndSetUIntT ( pTarget ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + epicsLockedSetUIntT ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return epicsLockedIncrSizeT ( pTarget ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return epicsLockedDecrSizeT ( pTarget ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + epicsLockedSetSizeT ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + return epicsLockedGetSizeT ( pTarget ); +} + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#else /* if defined ( OSD_ATOMIC_INLINE ) */ + +# define epicsAtomicIncrSizeT epicsLockedIncrSizeT +# define epicsAtomicDecrSizeT epicsLockedDecrSizeT +# define epicsAtomicSetSizeT epicsLockedSetSizeT +# define epicsAtomicSetUIntT epicsLockedSetUIntT +# define epicsAtomicGetSizeT epicsLockedGetSizeT +# define epicsAtomicTestAndSetUIntT epicsLockedTestAndSetUIntT + +#endif /* if defined ( OSD_ATOMIC_INLINE ) */ + +#endif /* epicsAtomicLocked_h */ + + diff --git a/src/libCom/osi/epicsAtomicOSD.cpp b/src/libCom/osi/epicsAtomicOSD.cpp new file mode 100644 index 000000000..a1b2ff4f5 --- /dev/null +++ b/src/libCom/osi/epicsAtomicOSD.cpp @@ -0,0 +1,45 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + + #include "epicsAtomic.h" + + /* + * OSD_ATOMIC_INLINE + * defined: define atomic functions in osdAtomic.h + * undefined: dont define atomic functions in osdAtomic.h + * + * OSD_ATOMIC_INLINE is typically set by the compiler specific file cdAtomic.h + * + * when we discover here that there is no implementation, and we guess that + * there isnt an inline keyword in the compiler then we define OSD_ATOMIC_INLINE + * empty and include osdAtomic.h to force an out of line implementation + * + * My first inclination was to place only one file of this type under os/default, + * but then this source file always includes default/osdAtomic.h, which isnt correct + * if a more specific os/xxx/osdAtromic.h exists, and so rather than duplicate an + * identical file in all of the os directories (that will get rediculous if there + * is ever a posix interface for the atomics) I moved it here to the osi directory. + * Another option would be to not make tthe current location be the first search + * in the gnu make VPATH, but I am somewhat nervous about changing something that + * fundamental in the build system. + * + * this behavior will work most of the time by defualt but it can always be + * replaced by an os specific implementation, which might be required if + * some of the functions are inline and some are not + */ + #ifndef OSD_ATOMIC_INLINE + # include "osdAtomic.h" + #endif + diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h new file mode 100644 index 000000000..7ea6385d4 --- /dev/null +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -0,0 +1,130 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef osdAtomic_h +#define osdAtomic_h + +#if defined ( OSD_ATOMIC_INLINE ) + +#include + +#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ +#include + +#include "epicsAssert.h" + +#define STRICT +#define VC_EXTRALEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* necessary for next two functions */ +STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) ); + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + InterlockedExchange ( pTarg, ( LONG ) newVal ); +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + long * const pTarg = ( LONG * ) ( pTarget ); + return InterlockedCompareExchange ( pTarg, 1, 0 ) == 0; +} + +/* + * on win32 a LONG is 32 bits, but I am concerned that + * we shouldnt use LONG_MAX here because with certain + * compilers a long will be 64 bits wide + */ +#define WIN32_LONG_MAX 0xffffffff +#if SIZE_MAX == WIN32_LONG_MAX + +/* + * necessary for next four functions + * + * looking at the MS documentation it appears that they will + * keep type long the same size as an int on 64 bit builds + */ +STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( size_t ) ); + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + LONG * const pTarg = ( LONG * ) pTarget; + return InterlockedIncrement ( pTarg ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + return InterlockedDecrement ( pTarg ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + InterlockedExchange ( pTarg, ( LONG ) newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + return InterlockedExchangeAdd ( pTarg, 0 ); +} + +#else /* SIZE_MAX == WIN32_LONG_MAX */ + +/* + * necessary for next four functions + */ +STATIC_ASSERT ( sizeof ( LONGLONG ) == sizeof ( size_t ) ); + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + LONGLONG * const pTarg = ( LONGLONG * ) pTarget; + return InterlockedIncrement64 ( pTarg ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); + return InterlockedDecrement64 ( pTarg ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); + InterlockedExchange64 ( pTarg, ( LONGLONG ) newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); + return InterlockedExchangeAdd64 ( pTarg, 0 ); +} + +#endif /* SIZE_MAX == WIN32_LONG_MAX */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#endif /* if defined ( OSD_ATOMIC_INLINE ) */ + +#endif /* ifndef osdAtomic_h */ diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.h b/src/libCom/osi/os/default/epicsAtomicOSD.h new file mode 100644 index 000000000..f8033d9d5 --- /dev/null +++ b/src/libCom/osi/os/default/epicsAtomicOSD.h @@ -0,0 +1,21 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef osdAtomic +#define osdAtomic + +#include "epicsAtomicLocked.h" + +#endif /* osdAtomic */ diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h new file mode 100644 index 000000000..b2521848d --- /dev/null +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -0,0 +1,105 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef osdAtomic_h +#define osdAtomic_h + +#if defined ( OSD_ATOMIC_INLINE ) + +/* + * atomic.h exists only in Solaris 10 or higher + */ +#if defined ( __SunOS_5_10 ) + +#include +#include + +#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + const uchar_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u ); + return oldVal == 0u; +} + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + atomic_swap_uint ( pTarget, newVal ); +} + +#if SIZE_MAX == UINT_MAX + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return atomic_inc_uint_nv ( pTarget ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return atomic_dec_uint_nv ( pTarget ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + atomic_swap_uint ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + return atomic_or_uint_nv ( pTarget, 0U ); +} + +#else /* SIZE_MAX == UINT_MAX */ + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return atomic_inc_ulong_nv ( pTarget ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return atomic_dec_ulong_nv ( pTarget ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + atomic_swap_ulong ( pTarget, newval ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + return atomic_or_ulong_nv ( pTarget, 0U ); +} + +#endif /* SIZE_MAX == UINT_MAX */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#else /* ifdef __SunOS_5_10 */ + +#include "epicsAtomicLocked.h" + +#endif /* ifdef __SunOS_5_10 */ + +#endif /* if defined ( OSD_ATOMIC_INLINE ) */ + +#endif /* osdAtomic_h */ diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h new file mode 100644 index 000000000..8b8abd900 --- /dev/null +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -0,0 +1,211 @@ +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne, LLC, as Operator of +* Argonne National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef osdAtomic_h +#define osdAtomic_h + +#if defined ( OSD_ATOMIC_INLINE ) + +#include "vxWorks.h" /* obtain the version of vxWorks */ + +/* + * With vxWorks 6.6 and later we need to use vxAtomicLib + * to implement this functionality correctly on SMP systems + */ +#if _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 + +#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ +#include + +#include +#include +#include "epicsAssert.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * we make the probably correct guess that if SIZE_MAX + * is the same as UINT_MAX then sizeof ( atomic_t ) + * will be the same as sizeof ( size_t ) + * + * if SIZE_MAX != UINT_MAX then its 64 bit vxWorks and + * WRS doesnt not supply at this time the atomic interface + * for 8 byte integers that is needed - so that architecture + * receives the lock synchronized version + */ +#if SIZE_MAX == UINT_MAX + +STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) ); + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + /* + * vxAtomicLib doc indicates that vxAtomicInc is + * implemented using unsigned arithmetic + */ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + const atomic_t oldVal = vxAtomicInc ( pTarg ) + 1; + return ( ( size_t ) ( oldVal ) ) + 1u; +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + /* + * vxAtomicLib doc indicates that vxAtomicDec is + * implemented using unsigned arithmetic + */ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + const atomic_t oldVal = vxAtomicDec ( pTarg ) - 1; + return ( ( size_t ) ( oldVal ) ) - 1u; +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + vxAtomicSet ( pTarg, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return ( size_t ) vxAtomicGet ( pTarg ); +} + +#else /* SIZE_MAX == UINT_MAX */ + +/* + * if its 64 bit vxWorks and the compiler doesnt + * have an intrinsic then maybe there isnt any way to + * implement these without using a global lock because + * size_t is bigger than atomic_t + */ +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return epicsLockedIncrSizeT ( pTarget ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return epicsLockedDecrSizeT ( pTarget ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + epicsLockedSetSizeT ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + return epicsLockedGetSizeT ( pTarget ); +} + +#endif /* SIZE_MAX == UINT_MAX */ + +STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + vxAtomicSet ( pTarg, newVal ); +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return vxCas ( pTarget, 0, 1 ) != 0; +} + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#else /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */ + +#include "intLib.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + /* + * no need for memory barrior since this + * is a single cpu system. + */ + const int key = intLock (); + const size_t result = ++(*pTarget); + intUnlock ( key ); + return result; +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + const int key = intLock (); + const size_t result = --(*pTarget); + intUnlock ( key ); + return result; +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + *pTarget = newVal; +} + +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + *pTarget = newVal; +} + +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +{ + STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); + int * const pTarg = ( int * ) ( pTarget ); + const BOOL weSetIt = vxTas ( pTarg, 0, 1 ); + return weSetIt != 0; +} + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#endif /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */ + +#endif /* if defined ( OSD_ATOMIC_INLINE ) */ + +#endif /* osdAtomic_h */ diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp new file mode 100644 index 000000000..464c20afe --- /dev/null +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -0,0 +1,499 @@ + +#include +#include + +#include "epicsInterrupt.h" +#include "epicsAtomic.h" +#include "epicsTime.h" +#include "epicsUnitTest.h" +#include "testMain.h" + +using std :: size_t; + +class RefCtr { +public: + RefCtr (); + ~RefCtr (); + void reference (); + void unreference (); +private: + size_t m_cnt; +}; + +class Ownership { +public: + Ownership (); + Ownership ( RefCtr & refCtr ); + Ownership ( const Ownership & ); + ~Ownership (); + Ownership & operator = ( const Ownership & ); +private: + RefCtr * _pRefCtr; + static RefCtr m_noOwnership; +}; + +inline RefCtr :: RefCtr () +{ + epicsAtomicSetSizeT ( & m_cnt, 0 ); +} + +inline RefCtr :: ~RefCtr () +{ + unsigned cnt = epicsAtomicGetSizeT ( & m_cnt ); + assert ( cnt == 0u ); +} + +inline void RefCtr :: reference () +{ + epicsAtomicIncrSizeT ( & m_cnt ); +} + +inline void RefCtr :: unreference () +{ + epicsAtomicDecrSizeT ( & m_cnt ); +} + +RefCtr Ownership :: m_noOwnership; + +inline Ownership :: Ownership () : + _pRefCtr ( & m_noOwnership ) +{ + m_noOwnership.reference (); +} + +inline Ownership :: Ownership ( RefCtr & refCtr ) : + _pRefCtr ( & refCtr ) +{ + refCtr.reference (); +} + +inline Ownership :: Ownership ( const Ownership & ownership ) : + _pRefCtr ( ownership._pRefCtr ) +{ + _pRefCtr->reference (); +} + +inline Ownership :: ~Ownership () +{ + _pRefCtr->unreference (); +} + +inline Ownership & Ownership :: + operator = ( const Ownership & ownership ) +{ + RefCtr * const pOldRefCtr = _pRefCtr; + _pRefCtr = ownership._pRefCtr; + _pRefCtr->reference (); + pOldRefCtr->unreference (); + return *this; +} + +inline Ownership retOwnership ( const Ownership & ownership ) +{ + return Ownership ( ownership ); +} + +inline Ownership recurRetOwner10 ( const Ownership & ownershipIn ) +{ + Ownership ownership = + retOwnership ( + retOwnership ( + retOwnership ( + retOwnership ( + retOwnership ( ownershipIn ) ) ) ) ); + return retOwnership ( + retOwnership ( + retOwnership ( + retOwnership ( + retOwnership ( ownership ) ) ) ) ); +} + +inline Ownership recurRetOwner100 ( const Ownership & ownershipIn ) +{ + Ownership ownership = + recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( ownershipIn ) ) ) ) ); + return recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( + recurRetOwner10 ( ownership ) ) ) ) ); +} + +inline Ownership recurRetOwner1000 ( const Ownership & ownershipIn ) +{ + Ownership ownership = + recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( ownershipIn ) ) ) ) ); + return recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( + recurRetOwner100 ( ownership ) ) ) ) ); +} + +inline void passRefOwnership ( const Ownership & ownershipIn, Ownership & ownershipOut ) +{ + ownershipOut = ownershipIn; +} + +inline void passRefOwnership10 ( const Ownership & ownershipIn, Ownership & ownershipOut ) +{ + Ownership ownershipTmp0; + passRefOwnership ( ownershipIn, ownershipTmp0 ); + Ownership ownershipTmp1; + passRefOwnership ( ownershipTmp0, ownershipTmp1 ); + Ownership ownershipTmp2; + passRefOwnership ( ownershipTmp1, ownershipTmp2 ); + Ownership ownershipTmp3; + passRefOwnership ( ownershipTmp2, ownershipTmp3 ); + Ownership ownershipTmp4; + passRefOwnership ( ownershipTmp3, ownershipTmp4 ); + Ownership ownershipTmp5; + passRefOwnership ( ownershipTmp4, ownershipTmp5 ); + Ownership ownershipTmp6; + passRefOwnership ( ownershipTmp5, ownershipTmp6 ); + Ownership ownershipTmp7; + passRefOwnership ( ownershipTmp6, ownershipTmp7 ); + Ownership ownershipTmp8; + passRefOwnership ( ownershipTmp7, ownershipTmp8 ); + passRefOwnership ( ownershipTmp8, ownershipOut ); +} + +inline void passRefOwnership100 ( const Ownership & ownershipIn, Ownership & ownershipOut ) +{ + Ownership ownershipTmp0; + passRefOwnership10 ( ownershipIn, ownershipTmp0 ); + Ownership ownershipTmp1; + passRefOwnership10 ( ownershipTmp0, ownershipTmp1 ); + Ownership ownershipTmp2; + passRefOwnership10 ( ownershipTmp1, ownershipTmp2 ); + Ownership ownershipTmp3; + passRefOwnership10 ( ownershipTmp2, ownershipTmp3 ); + Ownership ownershipTmp4; + passRefOwnership10 ( ownershipTmp3, ownershipTmp4 ); + Ownership ownershipTmp5; + passRefOwnership10 ( ownershipTmp4, ownershipTmp5 ); + Ownership ownershipTmp6; + passRefOwnership10 ( ownershipTmp5, ownershipTmp6 ); + Ownership ownershipTmp7; + passRefOwnership10 ( ownershipTmp6, ownershipTmp7 ); + Ownership ownershipTmp8; + passRefOwnership10 ( ownershipTmp7, ownershipTmp8 ); + passRefOwnership10 ( ownershipTmp8, ownershipOut ); +} + +inline void passRefOwnership1000 ( const Ownership & ownershipIn, Ownership & ownershipOut ) +{ + Ownership ownershipTmp0; + passRefOwnership100 ( ownershipIn, ownershipTmp0 ); + Ownership ownershipTmp1; + passRefOwnership100 ( ownershipTmp0, ownershipTmp1 ); + Ownership ownershipTmp2; + passRefOwnership100 ( ownershipTmp1, ownershipTmp2 ); + Ownership ownershipTmp3; + passRefOwnership100 ( ownershipTmp2, ownershipTmp3 ); + Ownership ownershipTmp4; + passRefOwnership100 ( ownershipTmp3, ownershipTmp4 ); + Ownership ownershipTmp5; + passRefOwnership100 ( ownershipTmp4, ownershipTmp5 ); + Ownership ownershipTmp6; + passRefOwnership100 ( ownershipTmp5, ownershipTmp6 ); + Ownership ownershipTmp7; + passRefOwnership100 ( ownershipTmp6, ownershipTmp7 ); + Ownership ownershipTmp8; + passRefOwnership100 ( ownershipTmp7, ownershipTmp8 ); + passRefOwnership100 ( ownershipTmp8, ownershipOut ); +} + +time_t extTime = 0; + +// tests the time it takes to perform a call to an external +// function and also increment an integer word. The +// epicsInterruptIsInterruptContext function is an +// out-of-line function implemented in a sharable library +// so hopefully it wont be optimized away. +inline void tenOrdinaryIncr ( size_t & target ) +{ + int result = 0; + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + result += epicsInterruptIsInterruptContext (); + target = static_cast < unsigned > ( result ); +} + +inline void oneHundredOrdinaryIncr ( size_t & target ) +{ + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); + tenOrdinaryIncr ( target ); +} + +inline void oneThousandOrdinaryIncr ( size_t & target ) +{ + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); + oneHundredOrdinaryIncr ( target ); +} + +inline void tenAtomicIncr ( size_t & target ) +{ + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); + epicsAtomicIncrSizeT ( & target ); +} + +inline void oneHundredAtomicIncr ( size_t & target ) +{ + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); + tenAtomicIncr ( target ); +} + +inline void oneThousandAtomicIncr ( size_t & target ) +{ + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); + oneHundredAtomicIncr ( target ); +} + +inline void tenAtomicTestAndSet ( unsigned & target ) +{ + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicTestAndSetUIntT ( & target ); +} + +inline void oneHundredAtomicTestAndSet ( unsigned & target ) +{ + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); + tenAtomicTestAndSet ( target ); +} + +inline void oneThousandAtomicTestAndSet ( unsigned & target ) +{ + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicTestAndSet ( target ); +} + +inline void tenAtomicSet ( size_t & target ) +{ + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); + epicsAtomicSetSizeT ( & target, 0 ); +} + +inline void oneHundredAtomicSet ( size_t & target ) +{ + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); + tenAtomicSet ( target ); +} + +inline void oneThousandAtomicSet ( size_t & target ) +{ + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); + oneHundredAtomicSet ( target ); +} + +static const unsigned N = 10000; + +void ordinaryIncrPerformance () +{ + epicsTime begin = epicsTime::getCurrent (); + size_t target; + epicsAtomicSetSizeT ( & target, 0 ); + for ( unsigned i = 0; i < N; i++ ) { + oneThousandOrdinaryIncr ( target ); + } + double delay = epicsTime::getCurrent () - begin; + testOk1 ( target == 0u ); + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "raw incr and a NOOP function call takes %f microseconds", delay ); +} + +void epicsAtomicIncrPerformance () +{ + epicsTime begin = epicsTime::getCurrent (); + size_t target; + epicsAtomicSetSizeT ( & target, 0 ); + for ( unsigned i = 0; i < N; i++ ) { + oneThousandAtomicIncr ( target ); + } + double delay = epicsTime::getCurrent () - begin; + testOk1 ( target == N * 1000u ); + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "epicsAtomicIncr() takes %f microseconds", delay ); +} + +void atomicCompareAndSetPerformance () +{ + epicsTime begin = epicsTime::getCurrent (); + size_t target; + epicsAtomicSetSizeT ( & target, 0 ); + testOk1 ( ! target ); + for ( unsigned i = 0; i < N; i++ ) { + oneThousandAtomicTestAndSet ( target ); + } + double delay = epicsTime::getCurrent () - begin; + testOk1 ( target ); + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "epicsAtomicCompareAndSet() takes %f microseconds", delay ); +} + +void recursiveOwnershipRetPerformance () +{ + RefCtr refCtr; + epicsTime begin = epicsTime::getCurrent (); + for ( unsigned i = 0; i < N; i++ ) { + Ownership ownership ( refCtr ); + recurRetOwner1000 ( ownership ); + } + double delay = epicsTime::getCurrent () - begin; + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "retOwnership() takes %f microseconds", delay ); +} + +void ownershipPassRefPerformance () +{ + RefCtr refCtr; + epicsTime begin = epicsTime::getCurrent (); + for ( unsigned i = 0; i < N; i++ ) { + Ownership ownershipSrc ( refCtr ); + Ownership ownershipDest; + passRefOwnership1000 ( ownershipSrc, ownershipDest ); + } + double delay = epicsTime::getCurrent () - begin; + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "passRefOwnership() takes %f microseconds", delay ); +} + +void epicsAtomicSetPerformance () +{ + epicsTime begin = epicsTime::getCurrent (); + unsigned target; + for ( unsigned i = 0; i < N; i++ ) { + oneThousandAtomicSet ( target ); + } + double delay = epicsTime::getCurrent () - begin; + testOk1 ( target == 0u ); + delay /= N * 1000u; // convert to delay per call + delay *= 1e6; // convert to micro seconds + testDiag ( "epicsAtomicSet() takes %f microseconds", delay ); +} + +MAIN(osiAtomicTest) +{ + testPlan(5); + // + // The tests running here are measuring fast + // functions so they tend to be impacted + // by where the cache lines are wrt to the + // virtual pages perhaps + // + epicsAtomicSetPerformance (); + ordinaryIncrPerformance (); + epicsAtomicIncrPerformance (); + recursiveOwnershipRetPerformance (); + ownershipPassRefPerformance (); + atomicCompareAndSetPerformance (); + return testDone(); +} diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c new file mode 100644 index 000000000..552e38aa6 --- /dev/null +++ b/src/libCom/test/epicsAtomicTest.c @@ -0,0 +1,117 @@ + +#include +#include + +#include "epicsAtomic.h" +#include "epicsTime.h" +#include "epicsThread.h" +#include "epicsUnitTest.h" +#include "testMain.h" + +typedef struct TestDataIncrDecr { + size_t m_testValue; + size_t m_testIterations; +} TestDataIncrDecr; + +static void incr ( void *arg ) +{ + TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg; + epicsAtomicIncrSizeT ( & pTestData->m_testValue ); + epicsAtomicIncrSizeT ( & pTestData->m_testIterations ); +} + +static void decr ( void *arg ) +{ + TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg; + epicsAtomicDecrSizeT ( & pTestData->m_testValue ); + epicsAtomicIncrSizeT ( & pTestData->m_testIterations ); +} + +typedef struct TestDataTNS { + unsigned m_testValue; + size_t m_testIterationsSet; + size_t m_testIterationsNotSet; +} TestDataTNS; + +int isModulo ( size_t N, size_t n ) +{ + return ( n % N ) == 0u; +} + +static void tns ( void *arg ) +{ + TestDataTNS * const pTestData = (TestDataTNS *) arg; + /* + * intentionally waste cpu and maximize + * contention for the shared data + */ + epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); + while ( ! epicsAtomicTestAndSetUIntT ( & pTestData->m_testValue ) ) { + } + epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); + epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u ); + epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); +} + +MAIN(osiAtomicTest) +{ + static const size_t N = 1000; + const unsigned int stackSize = + epicsThreadGetStackSize ( epicsThreadStackSmall ); + + testPlan(8); + + { + size_t i; + TestDataIncrDecr testData = { 0, N };; + epicsAtomicSetSizeT ( & testData.m_testValue, N ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, + "set/get %u", testData.m_testValue ); + epicsAtomicSetSizeT ( & testData.m_testIterations, 0u ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 0u, + "set/get %u", testData.m_testIterations ); + for ( i = 0u; i < N; i++ ) { + epicsThreadCreate ( "incr", + 50, stackSize, incr, & testData ); + epicsThreadCreate ( "decr", + 50, stackSize, decr, & testData ); + } + while ( testData.m_testIterations < 2 * N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N, + "incr/decr iterations %u", + testData.m_testIterations ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, + "incr/decr final value %u", + testData.m_testValue ); + } + + { + size_t i; + TestDataTNS testData = { 1, N, N }; + epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, + "set/get %u", testData.m_testIterationsSet ); + epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, + "set/get %u", testData.m_testIterationsNotSet ); + for ( i = 0u; i < N; i++ ) { + epicsThreadCreate ( "tns", + 50, stackSize, tns, & testData ); + } + epicsAtomicSetUIntT ( & testData.m_testValue, 0u ); + while ( testData.m_testIterationsSet < N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, + "test and set iterations %u", + testData.m_testIterationsSet ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, + "test and set not-set tracking = %u", + testData.m_testIterationsNotSet ); + } + + return testDone(); +} + From cedcddd0e80f4edcded749d96e9694fb8c281d01 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 09:51:05 -0600 Subject: [PATCH 05/61] track name changes --- src/libCom/osi/compiler/clang/epicsAtomicCD.h | 8 ++++---- src/libCom/osi/compiler/default/epicsAtomicCD.h | 8 ++++---- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 8 ++++---- src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 8 ++++---- src/libCom/osi/compiler/solStudio/epicsAtomicCD.h | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libCom/osi/compiler/clang/epicsAtomicCD.h b/src/libCom/osi/compiler/clang/epicsAtomicCD.h index ecb3833d1..fea011561 100644 --- a/src/libCom/osi/compiler/clang/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/clang/epicsAtomicCD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef cdAtomic_h -#define cdAtomic_h +#ifndef epicsAtomicCD_h +#define epicsAtomicCD_h #if defined ( __cplusplus ) # define OSD_ATOMIC_INLINE inline @@ -22,6 +22,6 @@ # define OSD_ATOMIC_INLINE __inline__ #endif -#include "osdAtomic.h" +#include "epicsAtomicOSD.h" -#endif /* cdAtomic_h */ +#endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/default/epicsAtomicCD.h b/src/libCom/osi/compiler/default/epicsAtomicCD.h index a4edb81c9..60171e377 100644 --- a/src/libCom/osi/compiler/default/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/default/epicsAtomicCD.h @@ -13,13 +13,13 @@ * johill@lanl.gov */ -#ifndef cdAtomic_h -#define cdAtomic_h +#ifndef epicsAtomicCD_h +#define epicsAtomicCD_h #if __STDC_VERSION__ >= 199901L || defined ( __cplusplus ) # define OSD_ATOMIC_INLINE inline #endif -#include "osdAtomic.h" +#include "epicsAtomicOSD.h" -#endif /* cdAtomic_h */ +#endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index 364a86e0d..f725a23cb 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef cdAtomic_h -#define cdAtomic_h +#ifndef epicsAtomicCD_h +#define epicsAtomicCD_h #ifndef __GNUC__ # error this header is only for use with the gnu compiler @@ -90,8 +90,8 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) * not available as gcc intrinsics so we * will employ an os specific inline solution */ -# include "osdAtomic.h" +# include "epicsAtomicOSD.h" #endif /* if GCC_ATOMIC_INTRINSICS_AVAIL */ -#endif /* cdAtomic_h */ +#endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index 1353d121e..17a3bec9a 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef cdAtomic_h -#define cdAtomic_h +#ifndef epicsAtomicCD_h +#define epicsAtomicCD_h #include "epicsAssert.h" @@ -157,9 +157,9 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) #if defined ( __cplusplus ) # define OSD_ATOMIC_INLINE inline -# include "osdAtomic.h" +# include "epicsAtomicOSD.h" #endif #endif /* ifdef _MSC_EXTENSIONS */ -#endif /* cdAtomic_h */ +#endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h index a69bb19bb..c72a3e203 100644 --- a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef cdAtomic_h -#define cdAtomic_h +#ifndef epicsAtomicCD_h +#define epicsAtomicCD_h #if defined ( __cplusplus ) # define OSD_ATOMIC_INLINE inline @@ -22,6 +22,6 @@ # define OSD_ATOMIC_INLINE __inline #endif -#include "osdAtomic.h" +#include "epicsAtomicOSD.h" -#endif /* cdAtomic_h */ +#endif /* epicsAtomicCD_h */ From 31f5ae048fb526df83f091d05850a9c5799911c9 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 09:51:05 -0600 Subject: [PATCH 06/61] track name changes --- src/libCom/osi/compiler/clang/epicsAtomicCD.h | 8 ++++---- src/libCom/osi/compiler/default/epicsAtomicCD.h | 8 ++++---- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 8 ++++---- src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 8 ++++---- src/libCom/osi/compiler/solStudio/epicsAtomicCD.h | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libCom/osi/compiler/clang/epicsAtomicCD.h b/src/libCom/osi/compiler/clang/epicsAtomicCD.h index ecb3833d1..fea011561 100644 --- a/src/libCom/osi/compiler/clang/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/clang/epicsAtomicCD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef cdAtomic_h -#define cdAtomic_h +#ifndef epicsAtomicCD_h +#define epicsAtomicCD_h #if defined ( __cplusplus ) # define OSD_ATOMIC_INLINE inline @@ -22,6 +22,6 @@ # define OSD_ATOMIC_INLINE __inline__ #endif -#include "osdAtomic.h" +#include "epicsAtomicOSD.h" -#endif /* cdAtomic_h */ +#endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/default/epicsAtomicCD.h b/src/libCom/osi/compiler/default/epicsAtomicCD.h index a4edb81c9..60171e377 100644 --- a/src/libCom/osi/compiler/default/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/default/epicsAtomicCD.h @@ -13,13 +13,13 @@ * johill@lanl.gov */ -#ifndef cdAtomic_h -#define cdAtomic_h +#ifndef epicsAtomicCD_h +#define epicsAtomicCD_h #if __STDC_VERSION__ >= 199901L || defined ( __cplusplus ) # define OSD_ATOMIC_INLINE inline #endif -#include "osdAtomic.h" +#include "epicsAtomicOSD.h" -#endif /* cdAtomic_h */ +#endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index 364a86e0d..f725a23cb 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef cdAtomic_h -#define cdAtomic_h +#ifndef epicsAtomicCD_h +#define epicsAtomicCD_h #ifndef __GNUC__ # error this header is only for use with the gnu compiler @@ -90,8 +90,8 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) * not available as gcc intrinsics so we * will employ an os specific inline solution */ -# include "osdAtomic.h" +# include "epicsAtomicOSD.h" #endif /* if GCC_ATOMIC_INTRINSICS_AVAIL */ -#endif /* cdAtomic_h */ +#endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index 1353d121e..17a3bec9a 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef cdAtomic_h -#define cdAtomic_h +#ifndef epicsAtomicCD_h +#define epicsAtomicCD_h #include "epicsAssert.h" @@ -157,9 +157,9 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) #if defined ( __cplusplus ) # define OSD_ATOMIC_INLINE inline -# include "osdAtomic.h" +# include "epicsAtomicOSD.h" #endif #endif /* ifdef _MSC_EXTENSIONS */ -#endif /* cdAtomic_h */ +#endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h index a69bb19bb..c72a3e203 100644 --- a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef cdAtomic_h -#define cdAtomic_h +#ifndef epicsAtomicCD_h +#define epicsAtomicCD_h #if defined ( __cplusplus ) # define OSD_ATOMIC_INLINE inline @@ -22,6 +22,6 @@ # define OSD_ATOMIC_INLINE __inline #endif -#include "osdAtomic.h" +#include "epicsAtomicOSD.h" -#endif /* cdAtomic_h */ +#endif /* epicsAtomicCD_h */ From e1e3ec6c22a4d6dd7dd9cdd9f08a8959c43a4b25 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 10:50:25 -0600 Subject: [PATCH 07/61] enable gcc atomic intrinsics on certain older gcc that does not advertize its atomics when targeting intel --- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index f725a23cb..c2b32557c 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -34,9 +34,13 @@ GCC_ATOMIC_CONCAT ( \ __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \ __SIZEOF_SIZE_T__ ) + +#define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \ + defined ( __i386 ) && ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 -#if GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ - && defined GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T +#if ( GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ + && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ + || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER #define OSD_ATOMIC_GCC From a05a83629571e80540ac2346bc5d4605e04e9eaf Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 10:50:25 -0600 Subject: [PATCH 08/61] enable gcc atomic intrinsics on certain older gcc that does not advertize its atomics when targeting intel --- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index f725a23cb..c2b32557c 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -34,9 +34,13 @@ GCC_ATOMIC_CONCAT ( \ __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \ __SIZEOF_SIZE_T__ ) + +#define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \ + defined ( __i386 ) && ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 -#if GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ - && defined GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T +#if ( GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ + && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ + || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER #define OSD_ATOMIC_GCC From b051875f22c7d405d629d4ede38503d295073fcf Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 11:14:37 -0600 Subject: [PATCH 09/61] changed test iterations to accomodate old systems --- src/libCom/test/epicsAtomicTest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index 552e38aa6..d668936b2 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -55,13 +55,13 @@ static void tns ( void *arg ) MAIN(osiAtomicTest) { - static const size_t N = 1000; const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); testPlan(8); { + static const size_t N = 100; size_t i; TestDataIncrDecr testData = { 0, N };; epicsAtomicSetSizeT ( & testData.m_testValue, N ); @@ -88,6 +88,7 @@ MAIN(osiAtomicTest) } { + static const size_t N = 10; size_t i; TestDataTNS testData = { 1, N, N }; epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); From d6cfa286b24713cd2aed45a83b4e6572fe543dc7 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 11:14:37 -0600 Subject: [PATCH 10/61] changed test iterations to accomodate old systems --- src/libCom/test/epicsAtomicTest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index 552e38aa6..d668936b2 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -55,13 +55,13 @@ static void tns ( void *arg ) MAIN(osiAtomicTest) { - static const size_t N = 1000; const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); testPlan(8); { + static const size_t N = 100; size_t i; TestDataIncrDecr testData = { 0, N };; epicsAtomicSetSizeT ( & testData.m_testValue, N ); @@ -88,6 +88,7 @@ MAIN(osiAtomicTest) } { + static const size_t N = 10; size_t i; TestDataTNS testData = { 1, N, N }; epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); From fc4a4d902484ac11f2fb02a040a1f53bedc08d34 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 16:23:50 -0600 Subject: [PATCH 11/61] o fixed include guard to match file names o fixed legacy vxWorks support --- src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 6 +-- src/libCom/osi/os/default/epicsAtomicOSD.h | 6 +-- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 6 +-- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 53 ++++++++++++---------- 4 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index 7ea6385d4..3c4ac85df 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef osdAtomic_h -#define osdAtomic_h +#ifndef epicsAtomicOSD_h +#define epicsAtomicOSD_h #if defined ( OSD_ATOMIC_INLINE ) @@ -127,4 +127,4 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) #endif /* if defined ( OSD_ATOMIC_INLINE ) */ -#endif /* ifndef osdAtomic_h */ +#endif /* ifndef epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.h b/src/libCom/osi/os/default/epicsAtomicOSD.h index f8033d9d5..0b250495b 100644 --- a/src/libCom/osi/os/default/epicsAtomicOSD.h +++ b/src/libCom/osi/os/default/epicsAtomicOSD.h @@ -13,9 +13,9 @@ * johill@lanl.gov */ -#ifndef osdAtomic -#define osdAtomic +#ifndef epicsAtomicOSD_h +#define epicsAtomicOSD_h #include "epicsAtomicLocked.h" -#endif /* osdAtomic */ +#endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index b2521848d..31359ee14 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef osdAtomic_h -#define osdAtomic_h +#ifndef epicsAtomicOSD_h +#define epicsAtomicOSD_h #if defined ( OSD_ATOMIC_INLINE ) @@ -102,4 +102,4 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) #endif /* if defined ( OSD_ATOMIC_INLINE ) */ -#endif /* osdAtomic_h */ +#endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 8b8abd900..f3e4edaa6 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -12,12 +12,13 @@ * johill@lanl.gov */ -#ifndef osdAtomic_h -#define osdAtomic_h +#ifndef epicsAtomicOSD_h +#define epicsAtomicOSD_h #if defined ( OSD_ATOMIC_INLINE ) #include "vxWorks.h" /* obtain the version of vxWorks */ +#include "epicsAssert.h" /* * With vxWorks 6.6 and later we need to use vxAtomicLib @@ -30,7 +31,6 @@ #include #include -#include "epicsAssert.h" #ifdef __cplusplus extern "C" { @@ -135,6 +135,7 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) #else /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */ +#include "vxLib.h" #include "intLib.h" #ifdef __cplusplus @@ -143,26 +144,34 @@ extern "C" { OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - /* - * no need for memory barrior since this - * is a single cpu system. - */ - const int key = intLock (); - const size_t result = ++(*pTarget); - intUnlock ( key ); - return result; +# ifdef __m68k__ + return ++(*pTarget); +# else + /* + * no need for memory barrior since this + * is a single cpu system. + */ + const int key = intLock (); + const size_t result = ++(*pTarget); + intUnlock ( key ); + return result; +# endif } OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - /* - * no need for memory barrior since this - * is a single cpu system - */ - const int key = intLock (); - const size_t result = --(*pTarget); - intUnlock ( key ); - return result; +# ifdef __m68k__ + return --(*pTarget); +# else + /* + * no need for memory barrior since this + * is a single cpu system + */ + const int key = intLock (); + const size_t result = --(*pTarget); + intUnlock ( key ); + return result; +#endif } OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) @@ -195,9 +204,7 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); - int * const pTarg = ( int * ) ( pTarget ); - const BOOL weSetIt = vxTas ( pTarg, 0, 1 ); - return weSetIt != 0; + return vxTas ( pTarget ); } #ifdef __cplusplus @@ -208,4 +215,4 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) #endif /* if defined ( OSD_ATOMIC_INLINE ) */ -#endif /* osdAtomic_h */ +#endif /* epicsAtomicOSD_h */ From deb74a10b7714d40e5a957fe22ef345d6973321c Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 16:23:50 -0600 Subject: [PATCH 12/61] o fixed include guard to match file names o fixed legacy vxWorks support --- src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 6 +-- src/libCom/osi/os/default/epicsAtomicOSD.h | 6 +-- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 6 +-- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 53 ++++++++++++---------- 4 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index 7ea6385d4..3c4ac85df 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef osdAtomic_h -#define osdAtomic_h +#ifndef epicsAtomicOSD_h +#define epicsAtomicOSD_h #if defined ( OSD_ATOMIC_INLINE ) @@ -127,4 +127,4 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) #endif /* if defined ( OSD_ATOMIC_INLINE ) */ -#endif /* ifndef osdAtomic_h */ +#endif /* ifndef epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.h b/src/libCom/osi/os/default/epicsAtomicOSD.h index f8033d9d5..0b250495b 100644 --- a/src/libCom/osi/os/default/epicsAtomicOSD.h +++ b/src/libCom/osi/os/default/epicsAtomicOSD.h @@ -13,9 +13,9 @@ * johill@lanl.gov */ -#ifndef osdAtomic -#define osdAtomic +#ifndef epicsAtomicOSD_h +#define epicsAtomicOSD_h #include "epicsAtomicLocked.h" -#endif /* osdAtomic */ +#endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index b2521848d..31359ee14 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -13,8 +13,8 @@ * johill@lanl.gov */ -#ifndef osdAtomic_h -#define osdAtomic_h +#ifndef epicsAtomicOSD_h +#define epicsAtomicOSD_h #if defined ( OSD_ATOMIC_INLINE ) @@ -102,4 +102,4 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) #endif /* if defined ( OSD_ATOMIC_INLINE ) */ -#endif /* osdAtomic_h */ +#endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 8b8abd900..f3e4edaa6 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -12,12 +12,13 @@ * johill@lanl.gov */ -#ifndef osdAtomic_h -#define osdAtomic_h +#ifndef epicsAtomicOSD_h +#define epicsAtomicOSD_h #if defined ( OSD_ATOMIC_INLINE ) #include "vxWorks.h" /* obtain the version of vxWorks */ +#include "epicsAssert.h" /* * With vxWorks 6.6 and later we need to use vxAtomicLib @@ -30,7 +31,6 @@ #include #include -#include "epicsAssert.h" #ifdef __cplusplus extern "C" { @@ -135,6 +135,7 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) #else /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */ +#include "vxLib.h" #include "intLib.h" #ifdef __cplusplus @@ -143,26 +144,34 @@ extern "C" { OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - /* - * no need for memory barrior since this - * is a single cpu system. - */ - const int key = intLock (); - const size_t result = ++(*pTarget); - intUnlock ( key ); - return result; +# ifdef __m68k__ + return ++(*pTarget); +# else + /* + * no need for memory barrior since this + * is a single cpu system. + */ + const int key = intLock (); + const size_t result = ++(*pTarget); + intUnlock ( key ); + return result; +# endif } OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - /* - * no need for memory barrior since this - * is a single cpu system - */ - const int key = intLock (); - const size_t result = --(*pTarget); - intUnlock ( key ); - return result; +# ifdef __m68k__ + return --(*pTarget); +# else + /* + * no need for memory barrior since this + * is a single cpu system + */ + const int key = intLock (); + const size_t result = --(*pTarget); + intUnlock ( key ); + return result; +#endif } OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) @@ -195,9 +204,7 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); - int * const pTarg = ( int * ) ( pTarget ); - const BOOL weSetIt = vxTas ( pTarg, 0, 1 ); - return weSetIt != 0; + return vxTas ( pTarget ); } #ifdef __cplusplus @@ -208,4 +215,4 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) #endif /* if defined ( OSD_ATOMIC_INLINE ) */ -#endif /* osdAtomic_h */ +#endif /* epicsAtomicOSD_h */ From ed6ad62cf780facaf9de6c59198d9bf2102d4645 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 17:11:29 -0600 Subject: [PATCH 13/61] fixed test names --- src/libCom/test/epicsAtomicPerform.cpp | 2 +- src/libCom/test/epicsAtomicTest.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp index 464c20afe..0b47dd900 100644 --- a/src/libCom/test/epicsAtomicPerform.cpp +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -480,7 +480,7 @@ void epicsAtomicSetPerformance () testDiag ( "epicsAtomicSet() takes %f microseconds", delay ); } -MAIN(osiAtomicTest) +MAIN(epicsAtomicPerform) { testPlan(5); // diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index d668936b2..bf5d2cbd2 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -53,7 +53,7 @@ static void tns ( void *arg ) epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); } -MAIN(osiAtomicTest) +MAIN(epicsAtomicTest) { const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); From 89e47e5fae482ed3ddd47fd66d840930865a5f27 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 17:11:29 -0600 Subject: [PATCH 14/61] fixed test names --- src/libCom/test/epicsAtomicPerform.cpp | 2 +- src/libCom/test/epicsAtomicTest.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp index 464c20afe..0b47dd900 100644 --- a/src/libCom/test/epicsAtomicPerform.cpp +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -480,7 +480,7 @@ void epicsAtomicSetPerformance () testDiag ( "epicsAtomicSet() takes %f microseconds", delay ); } -MAIN(osiAtomicTest) +MAIN(epicsAtomicPerform) { testPlan(5); // diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index d668936b2..bf5d2cbd2 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -53,7 +53,7 @@ static void tns ( void *arg ) epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); } -MAIN(osiAtomicTest) +MAIN(epicsAtomicTest) { const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); From 094072a93e5b8c7d09b23c6b2a050235d698db22 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 17:12:33 -0600 Subject: [PATCH 15/61] fixed modern vxWorks atomics --- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index f3e4edaa6..0230d1b24 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -26,9 +26,6 @@ */ #if _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 -#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ -#include - #include #include @@ -37,16 +34,16 @@ extern "C" { #endif /* __cplusplus */ /* - * we make the probably correct guess that if SIZE_MAX + * we make the probably correct guess that if ULONG_MAX * is the same as UINT_MAX then sizeof ( atomic_t ) * will be the same as sizeof ( size_t ) * - * if SIZE_MAX != UINT_MAX then its 64 bit vxWorks and + * if ULONG_MAX != UINT_MAX then its 64 bit vxWorks and * WRS doesnt not supply at this time the atomic interface * for 8 byte integers that is needed - so that architecture * receives the lock synchronized version */ -#if SIZE_MAX == UINT_MAX +#if ULONG_MAX == UINT_MAX STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) ); @@ -126,7 +123,7 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return vxCas ( pTarget, 0, 1 ) != 0; + return vxCas ( pTarg, 0, 1 ) != 0; } #ifdef __cplusplus From a3d9bf1e3f85793e08d802e6168a61417a608ea8 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 17:12:33 -0600 Subject: [PATCH 16/61] fixed modern vxWorks atomics --- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index f3e4edaa6..0230d1b24 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -26,9 +26,6 @@ */ #if _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 -#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ -#include - #include #include @@ -37,16 +34,16 @@ extern "C" { #endif /* __cplusplus */ /* - * we make the probably correct guess that if SIZE_MAX + * we make the probably correct guess that if ULONG_MAX * is the same as UINT_MAX then sizeof ( atomic_t ) * will be the same as sizeof ( size_t ) * - * if SIZE_MAX != UINT_MAX then its 64 bit vxWorks and + * if ULONG_MAX != UINT_MAX then its 64 bit vxWorks and * WRS doesnt not supply at this time the atomic interface * for 8 byte integers that is needed - so that architecture * receives the lock synchronized version */ -#if SIZE_MAX == UINT_MAX +#if ULONG_MAX == UINT_MAX STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) ); @@ -126,7 +123,7 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return vxCas ( pTarget, 0, 1 ) != 0; + return vxCas ( pTarg, 0, 1 ) != 0; } #ifdef __cplusplus From 33c40b23a1510fcdcde2e98b59740e132a6d2025 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 17:32:06 -0600 Subject: [PATCH 17/61] fixed epicsAtomicTestAndSetUIntT for solaris --- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 31359ee14..36273d965 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -35,7 +35,7 @@ extern "C" { OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { - const uchar_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u ); + const uint_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u ); return oldVal == 0u; } From 921df1dd5cd266448f0f7bfb575a6c865a26d900 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 17:32:06 -0600 Subject: [PATCH 18/61] fixed epicsAtomicTestAndSetUIntT for solaris --- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 31359ee14..36273d965 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -35,7 +35,7 @@ extern "C" { OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { - const uchar_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u ); + const uint_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u ); return oldVal == 0u; } From 76b8265dfd2c10c752b30b73aae13896f201ee09 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 17:33:19 -0600 Subject: [PATCH 19/61] o moved -march=i586 from CONFIG.arch.arch to CONFIG.Common.arch {cygwin-x86,win32-x86-cygwin,win32-x86-mingw o removed -march=i586 from CONFIG.linux-x86.linux-x86 o fixed compile errors in epicsAtomicOSD.h (I didnt have the proper version of solaris for initial testing here) --- configure/os/CONFIG.Common.cygwin-x86 | 3 ++ configure/os/CONFIG.Common.win32-x86-cygwin | 3 ++ configure/os/CONFIG.Common.win32-x86-mingw | 3 ++ src/libCom/osi/os/solaris/epicsAtomicOSD.h | 36 +++++++++++++++------ 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/configure/os/CONFIG.Common.cygwin-x86 b/configure/os/CONFIG.Common.cygwin-x86 index ee3653b76..f19c5c789 100644 --- a/configure/os/CONFIG.Common.cygwin-x86 +++ b/configure/os/CONFIG.Common.cygwin-x86 @@ -23,6 +23,9 @@ POSIX_LDLIBS += -lpthread ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 +# default minimum target architecture is pentium +ARCH_DEP_CFLAGS += -march=i586 + # Compiler defines _X86_ 1 # Compiler defines __MSVCRT__ 1 # Compiler defines __CYGWIN__ 1 diff --git a/configure/os/CONFIG.Common.win32-x86-cygwin b/configure/os/CONFIG.Common.win32-x86-cygwin index 49029cf2e..2e2e18aec 100644 --- a/configure/os/CONFIG.Common.win32-x86-cygwin +++ b/configure/os/CONFIG.Common.win32-x86-cygwin @@ -23,6 +23,9 @@ POSIX_LDLIBS += -lpthread ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 +# default minimum target architecture is pentium +ARCH_DEP_CFLAGS += -march=i586 + # With no-cygwin option: # compiler defines _X86_ 1 # compiler defines __MSVCRT__ 1 diff --git a/configure/os/CONFIG.Common.win32-x86-mingw b/configure/os/CONFIG.Common.win32-x86-mingw index f4ee2c1ff..00bfd650d 100644 --- a/configure/os/CONFIG.Common.win32-x86-mingw +++ b/configure/os/CONFIG.Common.win32-x86-mingw @@ -19,6 +19,9 @@ LDLIBS_READLINE = -lreadline -lcurses ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 +# default minimum target architecture is pentium +ARCH_DEP_CFLAGS += -march=i586 + # Compiler defines _X86_ 1 # Compiler defines __MSVCRT__ 1 # Compiler defines __MINGW32__ 1 diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 36273d965..5248c24ce 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -48,46 +48,64 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - return atomic_inc_uint_nv ( pTarget ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return atomic_inc_uint_nv ( pTarg ); } OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - return atomic_dec_uint_nv ( pTarget ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return atomic_dec_uint_nv ( pTarg ); } OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) { - atomic_swap_uint ( pTarget, newVal ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + atomic_swap_uint ( pTarg, newVal ); } OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - return atomic_or_uint_nv ( pTarget, 0U ); + /* + * we cast away const, but are careful not to modify + * the target + */ + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return atomic_or_uint_nv ( pTarg, 0U ); } -#else /* SIZE_MAX == UINT_MAX */ +#elif SIZE_MAX == ULONG_MAX OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - return atomic_inc_ulong_nv ( pTarget ); + unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); + return atomic_inc_ulong_nv ( pTarg ); } OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - return atomic_dec_ulong_nv ( pTarget ); + unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); + return atomic_dec_ulong_nv ( pTarg ); } OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) { - atomic_swap_ulong ( pTarget, newval ); + unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); + atomic_swap_ulong ( pTarg, newval ); } OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - return atomic_or_ulong_nv ( pTarget, 0U ); + /* + * we cast away const, but are careful not to modify + * the target + */ + unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); + return atomic_or_ulong_nv ( pTarg, 0UL ); } +#else +# error unsupported solaris architecture #endif /* SIZE_MAX == UINT_MAX */ #ifdef __cplusplus From eefc3b34e04706a4ed0985871a9eec57e5ae98f2 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 17:33:19 -0600 Subject: [PATCH 20/61] o moved -march=i586 from CONFIG.arch.arch to CONFIG.Common.arch {cygwin-x86,win32-x86-cygwin,win32-x86-mingw o removed -march=i586 from CONFIG.linux-x86.linux-x86 o fixed compile errors in epicsAtomicOSD.h (I didnt have the proper version of solaris for initial testing here) --- configure/os/CONFIG.Common.cygwin-x86 | 3 ++ configure/os/CONFIG.Common.win32-x86-cygwin | 3 ++ configure/os/CONFIG.Common.win32-x86-mingw | 3 ++ configure/os/CONFIG.linux-x86.linux-x86 | 5 --- .../CONFIG.win32-x86-cygwin.win32-x86-cygwin | 5 --- .../os/CONFIG.win32-x86-mingw.win32-x86-mingw | 5 --- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 36 ++++++++++++++----- 7 files changed, 36 insertions(+), 24 deletions(-) diff --git a/configure/os/CONFIG.Common.cygwin-x86 b/configure/os/CONFIG.Common.cygwin-x86 index ee3653b76..f19c5c789 100644 --- a/configure/os/CONFIG.Common.cygwin-x86 +++ b/configure/os/CONFIG.Common.cygwin-x86 @@ -23,6 +23,9 @@ POSIX_LDLIBS += -lpthread ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 +# default minimum target architecture is pentium +ARCH_DEP_CFLAGS += -march=i586 + # Compiler defines _X86_ 1 # Compiler defines __MSVCRT__ 1 # Compiler defines __CYGWIN__ 1 diff --git a/configure/os/CONFIG.Common.win32-x86-cygwin b/configure/os/CONFIG.Common.win32-x86-cygwin index 49029cf2e..2e2e18aec 100644 --- a/configure/os/CONFIG.Common.win32-x86-cygwin +++ b/configure/os/CONFIG.Common.win32-x86-cygwin @@ -23,6 +23,9 @@ POSIX_LDLIBS += -lpthread ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 +# default minimum target architecture is pentium +ARCH_DEP_CFLAGS += -march=i586 + # With no-cygwin option: # compiler defines _X86_ 1 # compiler defines __MSVCRT__ 1 diff --git a/configure/os/CONFIG.Common.win32-x86-mingw b/configure/os/CONFIG.Common.win32-x86-mingw index f4ee2c1ff..00bfd650d 100644 --- a/configure/os/CONFIG.Common.win32-x86-mingw +++ b/configure/os/CONFIG.Common.win32-x86-mingw @@ -19,6 +19,9 @@ LDLIBS_READLINE = -lreadline -lcurses ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 +# default minimum target architecture is pentium +ARCH_DEP_CFLAGS += -march=i586 + # Compiler defines _X86_ 1 # Compiler defines __MSVCRT__ 1 # Compiler defines __MINGW32__ 1 diff --git a/configure/os/CONFIG.linux-x86.linux-x86 b/configure/os/CONFIG.linux-x86.linux-x86 index 775680e11..6414b5ab0 100644 --- a/configure/os/CONFIG.linux-x86.linux-x86 +++ b/configure/os/CONFIG.linux-x86.linux-x86 @@ -16,8 +16,3 @@ STATIC_LDLIBS_NO= SHRLIB_LDFLAGS += -Wl,-h$@ LOADABLE_SHRLIB_LDFLAGS += -Wl,-h$@ - -# this means that atomic instrnsics are available, but that -# users with 486 processors and earlier will need specialized -# configure files -ARCH_DEP_CFLAGS += -march=i586 \ No newline at end of file diff --git a/configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin b/configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin index 5dca1b714..aa29f4d7a 100644 --- a/configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin +++ b/configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin @@ -23,11 +23,6 @@ SHRLIB_CFLAGS = SHRLIB_LDFLAGS = -shared -Wl,--out-implib,$(LIB_PREFIX)$*$(LIB_SUFFIX) LOADABLE_SHRLIB_LDFLAGS = -shared -Wl,--out-implib,$(LIB_PREFIX)$*$(LIB_SUFFIX) -# this means that atomic instrnsics are available, but that -# users with 486 processors and earlier will need specialized -# configure files -ARCH_DEP_CFLAGS += -march=i586 - # Override linking with gcc library from CONFIG.gnuCommon GNU_LDLIBS_YES = diff --git a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw index 32a6733ad..8309f8b45 100644 --- a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw @@ -18,11 +18,6 @@ RANLIB = ranlib RES=.coff RCCMD = windres $(INCLUDES) $< $@ -# this means that atomic instrnsics are available, but that -# users with 486 processors and earlier will need specialized -# configure files -ARCH_DEP_CFLAGS += -march=i586 - # No -fPIC avoids "-fPIC ignored for target (all code is position independent)" SHRLIB_CFLAGS = SHRLIB_LDFLAGS = -shared -Wl,--out-implib,$(LIB_PREFIX)$*$(LIB_SUFFIX) diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 36273d965..5248c24ce 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -48,46 +48,64 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - return atomic_inc_uint_nv ( pTarget ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return atomic_inc_uint_nv ( pTarg ); } OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - return atomic_dec_uint_nv ( pTarget ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return atomic_dec_uint_nv ( pTarg ); } OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) { - atomic_swap_uint ( pTarget, newVal ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + atomic_swap_uint ( pTarg, newVal ); } OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - return atomic_or_uint_nv ( pTarget, 0U ); + /* + * we cast away const, but are careful not to modify + * the target + */ + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return atomic_or_uint_nv ( pTarg, 0U ); } -#else /* SIZE_MAX == UINT_MAX */ +#elif SIZE_MAX == ULONG_MAX OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - return atomic_inc_ulong_nv ( pTarget ); + unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); + return atomic_inc_ulong_nv ( pTarg ); } OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - return atomic_dec_ulong_nv ( pTarget ); + unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); + return atomic_dec_ulong_nv ( pTarg ); } OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) { - atomic_swap_ulong ( pTarget, newval ); + unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); + atomic_swap_ulong ( pTarg, newval ); } OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - return atomic_or_ulong_nv ( pTarget, 0U ); + /* + * we cast away const, but are careful not to modify + * the target + */ + unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); + return atomic_or_ulong_nv ( pTarg, 0UL ); } +#else +# error unsupported solaris architecture #endif /* SIZE_MAX == UINT_MAX */ #ifdef __cplusplus From 092e1614850f9548d39efde1f5875bb3b8c14739 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 17:54:43 -0600 Subject: [PATCH 21/61] o fixed compile errors in epicsAtomicOSD.h (I didnt have the proper version of solaris to test) o fixed darwin compile errors (I dont have access to darwin) --- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 11 ++++------- src/libCom/test/epicsAtomicPerform.cpp | 8 ++++---- src/libCom/test/epicsAtomicTest.c | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index f3e4edaa6..0230d1b24 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -26,9 +26,6 @@ */ #if _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 -#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ -#include - #include #include @@ -37,16 +34,16 @@ extern "C" { #endif /* __cplusplus */ /* - * we make the probably correct guess that if SIZE_MAX + * we make the probably correct guess that if ULONG_MAX * is the same as UINT_MAX then sizeof ( atomic_t ) * will be the same as sizeof ( size_t ) * - * if SIZE_MAX != UINT_MAX then its 64 bit vxWorks and + * if ULONG_MAX != UINT_MAX then its 64 bit vxWorks and * WRS doesnt not supply at this time the atomic interface * for 8 byte integers that is needed - so that architecture * receives the lock synchronized version */ -#if SIZE_MAX == UINT_MAX +#if ULONG_MAX == UINT_MAX STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) ); @@ -126,7 +123,7 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return vxCas ( pTarget, 0, 1 ) != 0; + return vxCas ( pTarg, 0, 1 ) != 0; } #ifdef __cplusplus diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp index 464c20afe..283190932 100644 --- a/src/libCom/test/epicsAtomicPerform.cpp +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -424,8 +424,8 @@ void epicsAtomicIncrPerformance () void atomicCompareAndSetPerformance () { epicsTime begin = epicsTime::getCurrent (); - size_t target; - epicsAtomicSetSizeT ( & target, 0 ); + unsigned target; + epicsAtomicSetUIntT ( & target, 0 ); testOk1 ( ! target ); for ( unsigned i = 0; i < N; i++ ) { oneThousandAtomicTestAndSet ( target ); @@ -469,7 +469,7 @@ void ownershipPassRefPerformance () void epicsAtomicSetPerformance () { epicsTime begin = epicsTime::getCurrent (); - unsigned target; + size_t target; for ( unsigned i = 0; i < N; i++ ) { oneThousandAtomicSet ( target ); } @@ -480,7 +480,7 @@ void epicsAtomicSetPerformance () testDiag ( "epicsAtomicSet() takes %f microseconds", delay ); } -MAIN(osiAtomicTest) +MAIN(epicsAtomicPerform) { testPlan(5); // diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index d668936b2..bf5d2cbd2 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -53,7 +53,7 @@ static void tns ( void *arg ) epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); } -MAIN(osiAtomicTest) +MAIN(epicsAtomicTest) { const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); From e8bcfbe2c1ce872bd4c060487f931f0fae5ef8a0 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 17:54:43 -0600 Subject: [PATCH 22/61] o fixed compile errors in epicsAtomicOSD.h (I didnt have the proper version of solaris to test) o fixed darwin compile errors (I dont have access to darwin) --- LICENSE | 13 +++++++++++-- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 11 ++++------- src/libCom/test/epicsAtomicPerform.cpp | 10 +++++----- src/libCom/test/epicsAtomicTest.c | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/LICENSE b/LICENSE index ff9597ccf..da661c55f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,14 @@ -Copyright (c) 1991-2007 UChicago Argonne LLC and The Regents of the -University of California. All rights reserved. +Copyright (c) 2007-2011 UChicago Argonne LLC. All rights reserved. + +Copyright (c) 2006-2011. Los Alamos National Security, LLC. Some of this +material was produced under U.S. Government contract DE-AC52-06NA25396 +for Los Alamos National Laboratory (LANL), which is operated by Los Alamos +National Security, LLC for the U.S. Department of Energy. + +Copyright (c) 1991-2007 the University of Chicago. All rights reserved. + +Copyright (c) 1991-2006 The Regents of the University of California. +All rights reserved. EPICS BASE is distributed subject to the following license conditions: diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index f3e4edaa6..0230d1b24 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -26,9 +26,6 @@ */ #if _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 -#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ -#include - #include #include @@ -37,16 +34,16 @@ extern "C" { #endif /* __cplusplus */ /* - * we make the probably correct guess that if SIZE_MAX + * we make the probably correct guess that if ULONG_MAX * is the same as UINT_MAX then sizeof ( atomic_t ) * will be the same as sizeof ( size_t ) * - * if SIZE_MAX != UINT_MAX then its 64 bit vxWorks and + * if ULONG_MAX != UINT_MAX then its 64 bit vxWorks and * WRS doesnt not supply at this time the atomic interface * for 8 byte integers that is needed - so that architecture * receives the lock synchronized version */ -#if SIZE_MAX == UINT_MAX +#if ULONG_MAX == UINT_MAX STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) ); @@ -126,7 +123,7 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return vxCas ( pTarget, 0, 1 ) != 0; + return vxCas ( pTarg, 0, 1 ) != 0; } #ifdef __cplusplus diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp index 464c20afe..4a3a1bb19 100644 --- a/src/libCom/test/epicsAtomicPerform.cpp +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -424,8 +424,8 @@ void epicsAtomicIncrPerformance () void atomicCompareAndSetPerformance () { epicsTime begin = epicsTime::getCurrent (); - size_t target; - epicsAtomicSetSizeT ( & target, 0 ); + unsigned target; + epicsAtomicSetUIntT ( & target, 0 ); testOk1 ( ! target ); for ( unsigned i = 0; i < N; i++ ) { oneThousandAtomicTestAndSet ( target ); @@ -469,7 +469,7 @@ void ownershipPassRefPerformance () void epicsAtomicSetPerformance () { epicsTime begin = epicsTime::getCurrent (); - unsigned target; + size_t target; for ( unsigned i = 0; i < N; i++ ) { oneThousandAtomicSet ( target ); } @@ -480,7 +480,7 @@ void epicsAtomicSetPerformance () testDiag ( "epicsAtomicSet() takes %f microseconds", delay ); } -MAIN(osiAtomicTest) +MAIN(epicsAtomicPerform) { testPlan(5); // @@ -494,6 +494,6 @@ MAIN(osiAtomicTest) epicsAtomicIncrPerformance (); recursiveOwnershipRetPerformance (); ownershipPassRefPerformance (); - atomicCompareAndSetPerformance (); + atomicTestAndSetPerformance (); return testDone(); } diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index d668936b2..bf5d2cbd2 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -53,7 +53,7 @@ static void tns ( void *arg ) epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); } -MAIN(osiAtomicTest) +MAIN(epicsAtomicTest) { const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); From d522200295c29618564900a33437f1b7b5828a63 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 18:31:42 -0600 Subject: [PATCH 23/61] make the default minimum arch for 32 bit linux pentium --- configure/os/CONFIG.Common.linux-x86 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure/os/CONFIG.Common.linux-x86 b/configure/os/CONFIG.Common.linux-x86 index 22b9048e3..f3a2f5795 100644 --- a/configure/os/CONFIG.Common.linux-x86 +++ b/configure/os/CONFIG.Common.linux-x86 @@ -18,6 +18,9 @@ ARCH_DEP_CPPFLAGS += -D_X86_ OP_SYS_CFLAGS += -m32 OP_SYS_LDFLAGS += -m32 +# default minimum target architecture is pentium +ARCH_DEP_CFLAGS += -march=i586 + # If your crosscompiler name has a GNU target prefix like -gcc, # e.g. x86-redhat-linux-gcc, put a GNU_TARGET definition in # CONFIG_SITE..linux-x86 file, e.g. GNU_TARGET=x86-redhat-linux From 96723b66d7e7378659cb2d7319700f7185a782bd Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 18:31:42 -0600 Subject: [PATCH 24/61] make the default minimum arch for 32 bit linux pentium --- configure/os/CONFIG.Common.linux-x86 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure/os/CONFIG.Common.linux-x86 b/configure/os/CONFIG.Common.linux-x86 index f5157dc13..60ab38d0d 100644 --- a/configure/os/CONFIG.Common.linux-x86 +++ b/configure/os/CONFIG.Common.linux-x86 @@ -16,6 +16,9 @@ ARCH_DEP_CPPFLAGS += -D_X86_ ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 +# default minimum target architecture is pentium +ARCH_DEP_CFLAGS += -march=i586 + # If your crosscompiler name has a GNU target prefix like -gcc, # e.g. x86-redhat-linux-gcc, put a GNU_TARGET definition in # CONFIG_SITE..linux-x86 file, e.g. GNU_TARGET=x86-redhat-linux From 9e60e923e76c5356b8ac0fdb2565741fd70bece0 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 18:38:39 -0600 Subject: [PATCH 25/61] redo change reversed by merge --- src/libCom/test/epicsAtomicPerform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp index 283190932..5a8307598 100644 --- a/src/libCom/test/epicsAtomicPerform.cpp +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -421,7 +421,7 @@ void epicsAtomicIncrPerformance () testDiag ( "epicsAtomicIncr() takes %f microseconds", delay ); } -void atomicCompareAndSetPerformance () +void atomicTestAndSetPerformance () { epicsTime begin = epicsTime::getCurrent (); unsigned target; From 04c30aee0ebf840b6ce26b73e6677af479381e9b Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 18:38:39 -0600 Subject: [PATCH 26/61] redo change reversed by merge --- src/libCom/test/epicsAtomicPerform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp index 4a3a1bb19..a92d38536 100644 --- a/src/libCom/test/epicsAtomicPerform.cpp +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -421,7 +421,7 @@ void epicsAtomicIncrPerformance () testDiag ( "epicsAtomicIncr() takes %f microseconds", delay ); } -void atomicCompareAndSetPerformance () +void atomicTestAndSetPerformance () { epicsTime begin = epicsTime::getCurrent (); unsigned target; From 6f7ac559beec124951e4c26448c11bfee754bd86 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 9 Aug 2011 12:26:40 -0600 Subject: [PATCH 27/61] fixed solaris 64 compiler error (I dont have that version of solaris here) --- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 5248c24ce..952531750 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -91,7 +91,7 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) { unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); - atomic_swap_ulong ( pTarg, newval ); + atomic_swap_ulong ( pTarg, newVal ); } OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) From ca78732dac297a14f401a29812ec0828f35ca0a4 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 9 Aug 2011 12:26:40 -0600 Subject: [PATCH 28/61] fixed solaris 64 compiler error (I dont have that version of solaris here) --- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 5248c24ce..952531750 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -91,7 +91,7 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) { unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); - atomic_swap_ulong ( pTarg, newval ); + atomic_swap_ulong ( pTarg, newVal ); } OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) From 275df0471d50d31a9df8594e7c272ab07ade2a2d Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Wed, 10 Aug 2011 13:15:51 -0600 Subject: [PATCH 29/61] fixed test for earlier gcc supporting intel instrinsic atomic operations --- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index c2b32557c..29e0a728b 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -23,7 +23,7 @@ #define OSD_ATOMIC_INLINE __inline__ #define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B) -#define GCC_ATOMIC_CONCATR( A, B ) A ## B +#define GCC_ATOMIC_CONCATR( A, B ) ( A ## B ) #define GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ GCC_ATOMIC_CONCAT ( \ @@ -35,8 +35,13 @@ __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \ __SIZEOF_SIZE_T__ ) +#define GCC_ATOMIC_INTRINSICS_MIN_X86 \ + ( defined ( __i486 ) || defined ( __pentium ) || \ + defined ( __pentiumpro ) || defined ( __MMX__ ) ) + #define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \ - defined ( __i386 ) && ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 + ( GCC_ATOMIC_INTRINSICS_MIN_X86 && \ + ( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 ) ) #if ( GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ From bd2bccf98272dc816571add7b6c72204638676d4 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Wed, 10 Aug 2011 13:15:51 -0600 Subject: [PATCH 30/61] fixed test for earlier gcc supporting intel instrinsic atomic operations --- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index c2b32557c..29e0a728b 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -23,7 +23,7 @@ #define OSD_ATOMIC_INLINE __inline__ #define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B) -#define GCC_ATOMIC_CONCATR( A, B ) A ## B +#define GCC_ATOMIC_CONCATR( A, B ) ( A ## B ) #define GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ GCC_ATOMIC_CONCAT ( \ @@ -35,8 +35,13 @@ __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \ __SIZEOF_SIZE_T__ ) +#define GCC_ATOMIC_INTRINSICS_MIN_X86 \ + ( defined ( __i486 ) || defined ( __pentium ) || \ + defined ( __pentiumpro ) || defined ( __MMX__ ) ) + #define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \ - defined ( __i386 ) && ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 + ( GCC_ATOMIC_INTRINSICS_MIN_X86 && \ + ( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 ) ) #if ( GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ From 1f7f09e8186ff338dd7032e2f42020f1943212b7 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Thu, 11 Aug 2011 09:49:09 -0600 Subject: [PATCH 31/61] o removed "-march=i586" from configure/os/CONFIG.Common.cygwin-x86 configure/os/CONFIG.Common.linux-x86 configure/os/CONFIG.Common.win32-x86-cygwin configure/os/CONFIG.Common.win32-x86-mingw added commented out "-march=i586" to configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin added "-march=i586" to (I know that this compiler currently defaults to 386) configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw --- configure/os/CONFIG.Common.cygwin-x86 | 3 --- configure/os/CONFIG.Common.linux-x86 | 3 --- configure/os/CONFIG.Common.win32-x86-cygwin | 3 --- configure/os/CONFIG.Common.win32-x86-mingw | 3 --- configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 | 2 ++ configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin | 2 ++ configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw | 2 ++ 7 files changed, 6 insertions(+), 12 deletions(-) diff --git a/configure/os/CONFIG.Common.cygwin-x86 b/configure/os/CONFIG.Common.cygwin-x86 index f19c5c789..ee3653b76 100644 --- a/configure/os/CONFIG.Common.cygwin-x86 +++ b/configure/os/CONFIG.Common.cygwin-x86 @@ -23,9 +23,6 @@ POSIX_LDLIBS += -lpthread ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 -# default minimum target architecture is pentium -ARCH_DEP_CFLAGS += -march=i586 - # Compiler defines _X86_ 1 # Compiler defines __MSVCRT__ 1 # Compiler defines __CYGWIN__ 1 diff --git a/configure/os/CONFIG.Common.linux-x86 b/configure/os/CONFIG.Common.linux-x86 index f3a2f5795..22b9048e3 100644 --- a/configure/os/CONFIG.Common.linux-x86 +++ b/configure/os/CONFIG.Common.linux-x86 @@ -18,9 +18,6 @@ ARCH_DEP_CPPFLAGS += -D_X86_ OP_SYS_CFLAGS += -m32 OP_SYS_LDFLAGS += -m32 -# default minimum target architecture is pentium -ARCH_DEP_CFLAGS += -march=i586 - # If your crosscompiler name has a GNU target prefix like -gcc, # e.g. x86-redhat-linux-gcc, put a GNU_TARGET definition in # CONFIG_SITE..linux-x86 file, e.g. GNU_TARGET=x86-redhat-linux diff --git a/configure/os/CONFIG.Common.win32-x86-cygwin b/configure/os/CONFIG.Common.win32-x86-cygwin index 2e2e18aec..49029cf2e 100644 --- a/configure/os/CONFIG.Common.win32-x86-cygwin +++ b/configure/os/CONFIG.Common.win32-x86-cygwin @@ -23,9 +23,6 @@ POSIX_LDLIBS += -lpthread ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 -# default minimum target architecture is pentium -ARCH_DEP_CFLAGS += -march=i586 - # With no-cygwin option: # compiler defines _X86_ 1 # compiler defines __MSVCRT__ 1 diff --git a/configure/os/CONFIG.Common.win32-x86-mingw b/configure/os/CONFIG.Common.win32-x86-mingw index 00bfd650d..f4ee2c1ff 100644 --- a/configure/os/CONFIG.Common.win32-x86-mingw +++ b/configure/os/CONFIG.Common.win32-x86-mingw @@ -19,9 +19,6 @@ LDLIBS_READLINE = -lreadline -lcurses ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 -# default minimum target architecture is pentium -ARCH_DEP_CFLAGS += -march=i586 - # Compiler defines _X86_ 1 # Compiler defines __MSVCRT__ 1 # Compiler defines __MINGW32__ 1 diff --git a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 index 97e3cb1f3..be2e4a031 100644 --- a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 +++ b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 @@ -9,3 +9,5 @@ # GNU_DIR used when COMMANDLINE_LIBRARY is READLINE #GNU_DIR=C:/cygwin +# default minimum host hardware architecture +#ARCH_DEP_CFLAGS += -march=i586 \ No newline at end of file diff --git a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin index 139597f9c..21207d6d6 100644 --- a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin +++ b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin @@ -1,2 +1,4 @@ +# default minimum host hardware architecture +#ARCH_DEP_CFLAGS += -march=i586 diff --git a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw index 259d1e0c8..b82efdbc5 100644 --- a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw @@ -15,3 +15,5 @@ #LD = $(CMPLR_PREFIX)ld -r #RANLIB = $(CMPLR_PREFIX)ranlib +# default minimum host hardware architecture +ARCH_DEP_CFLAGS += -march=i586 \ No newline at end of file From 049e070b3a9d5d8fab772c5686d5368416bf426c Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Thu, 11 Aug 2011 09:49:09 -0600 Subject: [PATCH 32/61] o removed "-march=i586" from configure/os/CONFIG.Common.cygwin-x86 configure/os/CONFIG.Common.linux-x86 configure/os/CONFIG.Common.win32-x86-cygwin configure/os/CONFIG.Common.win32-x86-mingw added commented out "-march=i586" to configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin added "-march=i586" to (I know that this compiler currently defaults to 386) configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw --- configure/os/CONFIG.Common.cygwin-x86 | 3 --- configure/os/CONFIG.Common.linux-x86 | 3 --- configure/os/CONFIG.Common.win32-x86-cygwin | 3 --- configure/os/CONFIG.Common.win32-x86-mingw | 3 --- configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 | 2 ++ configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin | 2 ++ configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw | 2 ++ 7 files changed, 6 insertions(+), 12 deletions(-) diff --git a/configure/os/CONFIG.Common.cygwin-x86 b/configure/os/CONFIG.Common.cygwin-x86 index f19c5c789..ee3653b76 100644 --- a/configure/os/CONFIG.Common.cygwin-x86 +++ b/configure/os/CONFIG.Common.cygwin-x86 @@ -23,9 +23,6 @@ POSIX_LDLIBS += -lpthread ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 -# default minimum target architecture is pentium -ARCH_DEP_CFLAGS += -march=i586 - # Compiler defines _X86_ 1 # Compiler defines __MSVCRT__ 1 # Compiler defines __CYGWIN__ 1 diff --git a/configure/os/CONFIG.Common.linux-x86 b/configure/os/CONFIG.Common.linux-x86 index 60ab38d0d..f5157dc13 100644 --- a/configure/os/CONFIG.Common.linux-x86 +++ b/configure/os/CONFIG.Common.linux-x86 @@ -16,9 +16,6 @@ ARCH_DEP_CPPFLAGS += -D_X86_ ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 -# default minimum target architecture is pentium -ARCH_DEP_CFLAGS += -march=i586 - # If your crosscompiler name has a GNU target prefix like -gcc, # e.g. x86-redhat-linux-gcc, put a GNU_TARGET definition in # CONFIG_SITE..linux-x86 file, e.g. GNU_TARGET=x86-redhat-linux diff --git a/configure/os/CONFIG.Common.win32-x86-cygwin b/configure/os/CONFIG.Common.win32-x86-cygwin index 2e2e18aec..49029cf2e 100644 --- a/configure/os/CONFIG.Common.win32-x86-cygwin +++ b/configure/os/CONFIG.Common.win32-x86-cygwin @@ -23,9 +23,6 @@ POSIX_LDLIBS += -lpthread ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 -# default minimum target architecture is pentium -ARCH_DEP_CFLAGS += -march=i586 - # With no-cygwin option: # compiler defines _X86_ 1 # compiler defines __MSVCRT__ 1 diff --git a/configure/os/CONFIG.Common.win32-x86-mingw b/configure/os/CONFIG.Common.win32-x86-mingw index 00bfd650d..f4ee2c1ff 100644 --- a/configure/os/CONFIG.Common.win32-x86-mingw +++ b/configure/os/CONFIG.Common.win32-x86-mingw @@ -19,9 +19,6 @@ LDLIBS_READLINE = -lreadline -lcurses ARCH_DEP_CFLAGS += -m32 ARCH_DEP_LDFLAGS += -m32 -# default minimum target architecture is pentium -ARCH_DEP_CFLAGS += -march=i586 - # Compiler defines _X86_ 1 # Compiler defines __MSVCRT__ 1 # Compiler defines __MINGW32__ 1 diff --git a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 index 97e3cb1f3..be2e4a031 100644 --- a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 +++ b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 @@ -9,3 +9,5 @@ # GNU_DIR used when COMMANDLINE_LIBRARY is READLINE #GNU_DIR=C:/cygwin +# default minimum host hardware architecture +#ARCH_DEP_CFLAGS += -march=i586 \ No newline at end of file diff --git a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin index 139597f9c..21207d6d6 100644 --- a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin +++ b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin @@ -1,2 +1,4 @@ +# default minimum host hardware architecture +#ARCH_DEP_CFLAGS += -march=i586 diff --git a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw index 259d1e0c8..b82efdbc5 100644 --- a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw @@ -15,3 +15,5 @@ #LD = $(CMPLR_PREFIX)ld -r #RANLIB = $(CMPLR_PREFIX)ranlib +# default minimum host hardware architecture +ARCH_DEP_CFLAGS += -march=i586 \ No newline at end of file From c872c446683164bbb450b2dd12137874b6a30ff8 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 12 Aug 2011 10:06:09 -0600 Subject: [PATCH 33/61] added epicsAtomicGetUIntT for completeness --- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 6 +++ src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 8 ++- src/libCom/osi/epicsAtomic.h | 2 + src/libCom/osi/epicsAtomicLocked.cpp | 6 +++ src/libCom/osi/epicsAtomicLocked.h | 6 +++ src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 8 ++- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 10 ++++ src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 16 ++++++ src/libCom/test/epicsAtomicTest.c | 56 +++++++++++--------- 9 files changed, 90 insertions(+), 28 deletions(-) diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index 29e0a728b..faf1c7886 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -83,6 +83,12 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) return *pTarget; } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + __sync_synchronize (); + return *pTarget; +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { const size_t prev = __sync_lock_test_and_set ( pTarget, 1u ); diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index 17a3bec9a..08cd5ea31 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -66,7 +66,7 @@ extern "C" { #endif /* __cplusplus */ -/* necessary for next two functions */ +/* necessary for next three functions */ STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) ); OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) @@ -75,6 +75,12 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal _InterlockedExchange ( pTarg, ( long ) newVal ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + long * const pTarg = ( long * ) ( pTarget ); + return _InterlockedExchangeAdd ( pTarg, 0 ); +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { long * const pTarg = ( long * ) ( pTarget ); diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index c94c2de1e..72bb63e54 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -58,6 +58,7 @@ epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue * fetch target in cache, return new value of target */ epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget ); +epicsShareFunc unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ); /* * lock out other smp processors from accessing the target, @@ -84,6 +85,7 @@ epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); +epicsShareFunc unsigned epicsLockedGetUIntT ( const unsigned * pTarget ); epicsShareFunc unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ); #ifdef __cplusplus diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp index b9ea22757..625dea118 100644 --- a/src/libCom/osi/epicsAtomicLocked.cpp +++ b/src/libCom/osi/epicsAtomicLocked.cpp @@ -86,6 +86,12 @@ size_t epicsLockedGetSizeT ( const size_t * pTarget ) return *pTarget; } +unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) +{ + AtomicGuard atomicGuard; + return *pTarget; +} + unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ) { AtomicGuard atomicGuard; diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h index 0aec9c8b5..1ca29fd4c 100644 --- a/src/libCom/osi/epicsAtomicLocked.h +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -52,6 +52,11 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) return epicsLockedGetSizeT ( pTarget ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + return epicsLockedGetUIntT ( pTarget ); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ @@ -63,6 +68,7 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) # define epicsAtomicSetSizeT epicsLockedSetSizeT # define epicsAtomicSetUIntT epicsLockedSetUIntT # define epicsAtomicGetSizeT epicsLockedGetSizeT +# define epicsAtomicGetUIntT epicsLockedGetUIntT # define epicsAtomicTestAndSetUIntT epicsLockedTestAndSetUIntT #endif /* if defined ( OSD_ATOMIC_INLINE ) */ diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index 3c4ac85df..27b59b242 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -33,7 +33,7 @@ extern "C" { #endif /* __cplusplus */ -/* necessary for next two functions */ +/* necessary for next three functions */ STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) ); OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) @@ -42,6 +42,12 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal InterlockedExchange ( pTarg, ( LONG ) newVal ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + return InterlockedExchangeAdd ( pTarg, 0 ); +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { long * const pTarg = ( LONG * ) ( pTarget ); diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 952531750..7a6946899 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -44,6 +44,16 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal atomic_swap_uint ( pTarget, newVal ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + /* + * we cast away const, but are careful not to modify + * the target + */ + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return atomic_or_uint_nv ( pTarg, 0U ); +} + #if SIZE_MAX == UINT_MAX OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 0230d1b24..76ecf0c84 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -126,6 +126,13 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) return vxCas ( pTarg, 0, 1 ) != 0; } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return ( unsigned ) vxAtomicGet ( pTarg ); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ @@ -198,6 +205,15 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) return *pTarget; } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + return *pTarget; +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index bf5d2cbd2..5e0760b44 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -48,6 +48,8 @@ static void tns ( void *arg ) epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); while ( ! epicsAtomicTestAndSetUIntT ( & pTestData->m_testValue ) ) { } + testOk ( epicsAtomicGetUIntT ( & pTestData->m_testValue ), + "test and set must leave operand in true state" ); epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u ); epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); @@ -58,59 +60,61 @@ MAIN(epicsAtomicTest) const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); - testPlan(8); + static const size_t N_incrDecr = 100; + static const size_t N_testAndSet = 10; + + testPlan( 9 + N_testAndSet ); { - static const size_t N = 100; + size_t i; - TestDataIncrDecr testData = { 0, N };; - epicsAtomicSetSizeT ( & testData.m_testValue, N ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, + TestDataIncrDecr testData = { 0, N_incrDecr }; + epicsAtomicSetSizeT ( & testData.m_testValue, N_incrDecr ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr, "set/get %u", testData.m_testValue ); epicsAtomicSetSizeT ( & testData.m_testIterations, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 0u, "set/get %u", testData.m_testIterations ); - for ( i = 0u; i < N; i++ ) { - epicsThreadCreate ( "incr", - 50, stackSize, incr, & testData ); - epicsThreadCreate ( "decr", - 50, stackSize, decr, & testData ); + for ( i = 0u; i < N_incrDecr; i++ ) { + epicsThreadCreate ( "incr", 50, stackSize, incr, & testData ); + epicsThreadCreate ( "decr", 50, stackSize, decr, & testData ); } - while ( testData.m_testIterations < 2 * N ) { + while ( testData.m_testIterations < 2 * N_incrDecr ) { epicsThreadSleep ( 0.01 ); } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N, - "incr/decr iterations %u", - testData.m_testIterations ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, - "incr/decr final value %u", - testData.m_testValue ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N_incrDecr, + "incr/decr iterations %u", testData.m_testIterations ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr, + "incr/decr final value %u", testData.m_testValue ); } { - static const size_t N = 10; size_t i; - TestDataTNS testData = { 1, N, N }; + TestDataTNS testData = { 1, N_testAndSet, N_testAndSet }; epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, "set/get %u", testData.m_testIterationsSet ); epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, "set/get %u", testData.m_testIterationsNotSet ); - for ( i = 0u; i < N; i++ ) { + for ( i = 0u; i < N_testAndSet; i++ ) { epicsThreadCreate ( "tns", 50, stackSize, tns, & testData ); } epicsAtomicSetUIntT ( & testData.m_testValue, 0u ); - while ( testData.m_testIterationsSet < N ) { + while ( testData.m_testIterationsSet < N_testAndSet ) { epicsThreadSleep ( 0.01 ); } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, - "test and set iterations %u", - testData.m_testIterationsSet ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N_testAndSet, + "test and set iterations %u", testData.m_testIterationsSet ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "test and set not-set tracking = %u", - testData.m_testIterationsNotSet ); + "test and set not-set tracking = %u", testData.m_testIterationsNotSet ); + { + static unsigned setVal = 5; + epicsAtomicSetUIntT ( & testData.m_testValue, setVal ); + testOk ( epicsAtomicGetUIntT ( & testData.m_testValue ) == setVal, + "unsigned version of set and get must concur" ); + } } return testDone(); From a50482a0c9d46cab83df9243359a506f1d579cf9 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 12 Aug 2011 10:06:09 -0600 Subject: [PATCH 34/61] added epicsAtomicGetUIntT for completeness --- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 6 +++ src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 8 ++- src/libCom/osi/epicsAtomic.h | 2 + src/libCom/osi/epicsAtomicLocked.cpp | 6 +++ src/libCom/osi/epicsAtomicLocked.h | 6 +++ src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 8 ++- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 10 ++++ src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 16 ++++++ src/libCom/test/epicsAtomicTest.c | 56 +++++++++++--------- 9 files changed, 90 insertions(+), 28 deletions(-) diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index 29e0a728b..faf1c7886 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -83,6 +83,12 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) return *pTarget; } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + __sync_synchronize (); + return *pTarget; +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { const size_t prev = __sync_lock_test_and_set ( pTarget, 1u ); diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index 17a3bec9a..08cd5ea31 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -66,7 +66,7 @@ extern "C" { #endif /* __cplusplus */ -/* necessary for next two functions */ +/* necessary for next three functions */ STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) ); OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) @@ -75,6 +75,12 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal _InterlockedExchange ( pTarg, ( long ) newVal ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + long * const pTarg = ( long * ) ( pTarget ); + return _InterlockedExchangeAdd ( pTarg, 0 ); +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { long * const pTarg = ( long * ) ( pTarget ); diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index c94c2de1e..72bb63e54 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -58,6 +58,7 @@ epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue * fetch target in cache, return new value of target */ epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget ); +epicsShareFunc unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ); /* * lock out other smp processors from accessing the target, @@ -84,6 +85,7 @@ epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); +epicsShareFunc unsigned epicsLockedGetUIntT ( const unsigned * pTarget ); epicsShareFunc unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ); #ifdef __cplusplus diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp index b9ea22757..625dea118 100644 --- a/src/libCom/osi/epicsAtomicLocked.cpp +++ b/src/libCom/osi/epicsAtomicLocked.cpp @@ -86,6 +86,12 @@ size_t epicsLockedGetSizeT ( const size_t * pTarget ) return *pTarget; } +unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) +{ + AtomicGuard atomicGuard; + return *pTarget; +} + unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ) { AtomicGuard atomicGuard; diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h index 0aec9c8b5..1ca29fd4c 100644 --- a/src/libCom/osi/epicsAtomicLocked.h +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -52,6 +52,11 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) return epicsLockedGetSizeT ( pTarget ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + return epicsLockedGetUIntT ( pTarget ); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ @@ -63,6 +68,7 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) # define epicsAtomicSetSizeT epicsLockedSetSizeT # define epicsAtomicSetUIntT epicsLockedSetUIntT # define epicsAtomicGetSizeT epicsLockedGetSizeT +# define epicsAtomicGetUIntT epicsLockedGetUIntT # define epicsAtomicTestAndSetUIntT epicsLockedTestAndSetUIntT #endif /* if defined ( OSD_ATOMIC_INLINE ) */ diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index 3c4ac85df..27b59b242 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -33,7 +33,7 @@ extern "C" { #endif /* __cplusplus */ -/* necessary for next two functions */ +/* necessary for next three functions */ STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) ); OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) @@ -42,6 +42,12 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal InterlockedExchange ( pTarg, ( LONG ) newVal ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + return InterlockedExchangeAdd ( pTarg, 0 ); +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { long * const pTarg = ( LONG * ) ( pTarget ); diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 952531750..7a6946899 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -44,6 +44,16 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal atomic_swap_uint ( pTarget, newVal ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + /* + * we cast away const, but are careful not to modify + * the target + */ + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return atomic_or_uint_nv ( pTarg, 0U ); +} + #if SIZE_MAX == UINT_MAX OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 0230d1b24..76ecf0c84 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -126,6 +126,13 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) return vxCas ( pTarg, 0, 1 ) != 0; } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return ( unsigned ) vxAtomicGet ( pTarg ); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ @@ -198,6 +205,15 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) return *pTarget; } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + return *pTarget; +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index bf5d2cbd2..5e0760b44 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -48,6 +48,8 @@ static void tns ( void *arg ) epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); while ( ! epicsAtomicTestAndSetUIntT ( & pTestData->m_testValue ) ) { } + testOk ( epicsAtomicGetUIntT ( & pTestData->m_testValue ), + "test and set must leave operand in true state" ); epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u ); epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); @@ -58,59 +60,61 @@ MAIN(epicsAtomicTest) const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); - testPlan(8); + static const size_t N_incrDecr = 100; + static const size_t N_testAndSet = 10; + + testPlan( 9 + N_testAndSet ); { - static const size_t N = 100; + size_t i; - TestDataIncrDecr testData = { 0, N };; - epicsAtomicSetSizeT ( & testData.m_testValue, N ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, + TestDataIncrDecr testData = { 0, N_incrDecr }; + epicsAtomicSetSizeT ( & testData.m_testValue, N_incrDecr ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr, "set/get %u", testData.m_testValue ); epicsAtomicSetSizeT ( & testData.m_testIterations, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 0u, "set/get %u", testData.m_testIterations ); - for ( i = 0u; i < N; i++ ) { - epicsThreadCreate ( "incr", - 50, stackSize, incr, & testData ); - epicsThreadCreate ( "decr", - 50, stackSize, decr, & testData ); + for ( i = 0u; i < N_incrDecr; i++ ) { + epicsThreadCreate ( "incr", 50, stackSize, incr, & testData ); + epicsThreadCreate ( "decr", 50, stackSize, decr, & testData ); } - while ( testData.m_testIterations < 2 * N ) { + while ( testData.m_testIterations < 2 * N_incrDecr ) { epicsThreadSleep ( 0.01 ); } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N, - "incr/decr iterations %u", - testData.m_testIterations ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, - "incr/decr final value %u", - testData.m_testValue ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N_incrDecr, + "incr/decr iterations %u", testData.m_testIterations ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr, + "incr/decr final value %u", testData.m_testValue ); } { - static const size_t N = 10; size_t i; - TestDataTNS testData = { 1, N, N }; + TestDataTNS testData = { 1, N_testAndSet, N_testAndSet }; epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, "set/get %u", testData.m_testIterationsSet ); epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, "set/get %u", testData.m_testIterationsNotSet ); - for ( i = 0u; i < N; i++ ) { + for ( i = 0u; i < N_testAndSet; i++ ) { epicsThreadCreate ( "tns", 50, stackSize, tns, & testData ); } epicsAtomicSetUIntT ( & testData.m_testValue, 0u ); - while ( testData.m_testIterationsSet < N ) { + while ( testData.m_testIterationsSet < N_testAndSet ) { epicsThreadSleep ( 0.01 ); } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, - "test and set iterations %u", - testData.m_testIterationsSet ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N_testAndSet, + "test and set iterations %u", testData.m_testIterationsSet ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "test and set not-set tracking = %u", - testData.m_testIterationsNotSet ); + "test and set not-set tracking = %u", testData.m_testIterationsNotSet ); + { + static unsigned setVal = 5; + epicsAtomicSetUIntT ( & testData.m_testValue, setVal ); + testOk ( epicsAtomicGetUIntT ( & testData.m_testValue ) == setVal, + "unsigned version of set and get must concur" ); + } } return testDone(); From bd1b1479f466bf9de72113ab1eeb2b9959d8b006 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 15 Aug 2011 17:00:01 -0600 Subject: [PATCH 35/61] o no longer need to define OSD_ATOMIC_GCC o removed function epicsAtomicTestAndSetUIntT o added new functions epicsAtomicSetPtrT epicsAtomicGetPtrT epicsAtomicCmpAndSwapUIntT epicsAtomicCmpAndSwapPtrT o changed msvc intrinsics to define memory fence o fixed mutex synchronized version so that its slow, but correct if the c++ compiler doesnt synchronized local scope static initialization o changed most of the set/get methods to use memory barriers instead of some other primitive o added additional tests --- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 37 +++++- src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 112 ++++++++++------- src/libCom/osi/epicsAtomic.h | 32 +++-- src/libCom/osi/epicsAtomicLocked.cpp | 57 +++++++-- src/libCom/osi/epicsAtomicLocked.h | 42 +++++-- src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 96 +++++++++------ src/libCom/osi/os/solaris/epicsAtomicOSD.h | 109 +++++++--------- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 109 ++++++++++++++-- src/libCom/test/epicsAtomicPerform.cpp | 74 +++++------ src/libCom/test/epicsAtomicTest.c | 123 +++++++++++++------ 10 files changed, 525 insertions(+), 266 deletions(-) diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index faf1c7886..8b06bd7bb 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -39,16 +39,17 @@ ( defined ( __i486 ) || defined ( __pentium ) || \ defined ( __pentiumpro ) || defined ( __MMX__ ) ) +#define GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER \ + ( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 ) + #define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \ ( GCC_ATOMIC_INTRINSICS_MIN_X86 && \ - ( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 ) ) + GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER ) #if ( GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER -#define OSD_ATOMIC_GCC - #ifdef __cplusplus extern "C" { #endif @@ -77,6 +78,13 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, __sync_synchronize (); } +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT newValue ) +{ + *pTarget = newValue; + __sync_synchronize (); +} + OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { __sync_synchronize (); @@ -89,10 +97,22 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) { - const size_t prev = __sync_lock_test_and_set ( pTarget, 1u ); - return prev == 0; + __sync_synchronize (); + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) +{ + return __sync_val_compare_and_swap ( pTarget, oldVal, newVal); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + return __sync_val_compare_and_swap ( pTarget, oldVal, newVal); } #ifdef __cplusplus @@ -101,6 +121,11 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) #else /* if GCC_ATOMIC_INTRINSICS_AVAIL */ +# if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER && __i386 + /* 386 hardware is probably rare today even in embedded systems */ +# warning "this code will run much faster if specifying i486 or better" +# endif + /* * not available as gcc intrinsics so we * will employ an os specific inline solution diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index 08cd5ea31..4923664e7 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -24,21 +24,6 @@ #ifdef _MSC_EXTENSIONS -/* - * I have discovered an anomaly in visual c++ where - * the DLL instantiation of an exported inline interface - * does not occur in a c++ code unless "inline" is used. - */ -#if defined ( __cplusplus ) -# define OSD_ATOMIC_INLINE inline -#elif defined ( _MSC_VER ) -# define OSD_ATOMIC_INLINE __inline -#endif - -#if defined ( _M_X64 ) || defined ( _M_IA64 ) -# define OSD_ATOMIC_64 -#endif /* defined ( _M_X64 ) || defined ( _M_IA64 ) */ - #include #pragma intrinsic ( _InterlockedExchange ) @@ -54,6 +39,33 @@ # pragma intrinsic ( _InterlockedExchangeAdd64 ) #endif +#if _MSC_VER >= 1200 +# define OSD_ATOMIC_INLINE __forceinline +#else +# define OSD_ATOMIC_INLINE __inline +#endif + +#if defined ( _M_IX86 ) +# pragma warning( push ) +# pragma warning( disable : 4793 ) + OSD_ATOMIC_INLINE void OSD_ATOMIC_SYNC () + { + long fence; + __asm { xchg fence, eax } + } +# pragma warning( pop ) +#elif defined ( _M_X64 ) +# define OSD_ATOMIC_64 +# pragma intrinsic ( __faststorefence ) +# define OSD_ATOMIC_SYNC __faststorefence +#elif defined ( _M_IA64 ) +# define OSD_ATOMIC_64 +# pragma intrinsic ( __mf ) +# define OSD_ATOMIC_SYNC __mf +#else +# error unexpected target architecture, msvc version of epicsAtomicCD.h +#endif + /* * The windows doc appears to recommend defining InterlockedExchange * to be _InterlockedExchange to cause it to be an intrinsic, but that @@ -71,27 +83,53 @@ STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) ); OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) { - long * const pTarg = ( long * ) ( pTarget ); - _InterlockedExchange ( pTarg, ( long ) newVal ); + *pTarget = newVal; + OSD_ATOMIC_SYNC (); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + *pTarget = newVal; + OSD_ATOMIC_SYNC (); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT newVal ) +{ + *pTarget = newVal; + OSD_ATOMIC_SYNC (); } OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { - long * const pTarg = ( long * ) ( pTarget ); - return _InterlockedExchangeAdd ( pTarg, 0 ); + OSD_ATOMIC_SYNC (); + return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + OSD_ATOMIC_SYNC (); + return *pTarget; +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + OSD_ATOMIC_SYNC (); + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) { long * const pTarg = ( long * ) ( pTarget ); - return _InterlockedCompareExchange ( pTarg, 1, 0 ) == 0; + return (unsigned) _InterlockedCompareExchange ( pTarg, + (long) newVal, (long) oldVal ); } - #if ! OSD_ATOMIC_64 /* - * necessary for next four functions + * necessary for next five functions * * looking at the MS documentation it appears that they will * keep type long the same size as an int on 64 bit builds @@ -110,22 +148,18 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) return _InterlockedDecrement ( pTarg ); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { long * const pTarg = ( long * ) ( pTarget ); - _InterlockedExchange ( pTarg, ( long ) newVal ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - long * const pTarg = ( long * ) ( pTarget ); - return _InterlockedExchangeAdd ( pTarg, 0 ); + return (EpicsAtomicPtrT) _InterlockedCompareExchange ( pTarg, + (long) newVal, (long) oldVal ); } #else /* ! OSD_ATOMIC_64 */ /* - * necessary for next four functions + * necessary for next five functions */ STATIC_ASSERT ( sizeof ( long long ) == sizeof ( size_t ) ); @@ -141,16 +175,12 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) return _InterlockedDecrement64 ( pTarg ); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { - long long * const pTarg = ( long long * ) ( pTarget ); - _InterlockedExchange64 ( pTarg, ( long long ) newVal ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - long long * const pTarg = ( long long * ) ( pTarget ); - return _InterlockedExchangeAdd64 ( pTarg, 0 ); + long long * const pTarg = ( longlong * ) ( pTarget ); + return (EpicsAtomicPtrT) _InterlockedCompareExchange64 ( pTarg, + (long long) newVal, (long long) oldVal ); } #endif /* ! OSD_ATOMIC_64 */ diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index 72bb63e54..b444b1240 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -24,6 +24,8 @@ extern "C" { #endif +typedef void * EpicsAtomicPtrT; + /* * lock out other smp processors from accessing the target, * sync target in cache, add one to target, flush target in @@ -53,26 +55,31 @@ epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget ); */ epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue ); epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue ); +epicsShareFunc void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue ); /* * fetch target in cache, return new value of target */ epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget ); epicsShareFunc unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ); +epicsShareFunc EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ); /* * lock out other smp processors from accessing the target, - * sync target in cache, if target is zero set target to - * non-zero (true) value, flush target in cache, allow out - * other smp processors to access the target, return true if - * this request changed the target from a zero value to a - * non-zero (true) value and otherwise false + * sync target in cache, if target is equal to oldVal set target + * to newVal, flush target in cache, allow other smp processors + * to access the target, return the original value stored in the + * target * - * test and set is chosen as the primitive here because, - * compared to comapare-and-swap it is more likely to - * be implemented atomically on old architectures such as 68k + * !!!! beware, this will not guarantee an atomic operation + * !!!! on legacy vxWorks (prior to 6.6) if the target operand + * !!!! is on a multi-commander bus (such as the VME bus) */ -epicsShareFunc unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ); +epicsShareFunc unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ); +epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); + /* * the following are, never inline and always synchronized by a global @@ -84,9 +91,14 @@ epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget ); epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); +epicsShareFunc void epicsLockedSetPtrT ( unsigned * pTarget, EpicsAtomicPtrT newVal ); epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); epicsShareFunc unsigned epicsLockedGetUIntT ( const unsigned * pTarget ); -epicsShareFunc unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ); +epicsShareFunc EpicsAtomicPtrT epicsLockedGetPtrT ( const unsigned * pTarget ); +epicsShareFunc unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldval, unsigned newval ); +epicsShareFunc EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); #ifdef __cplusplus } /* end of extern "C" */ diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp index 625dea118..65a64fb83 100644 --- a/src/libCom/osi/epicsAtomicLocked.cpp +++ b/src/libCom/osi/epicsAtomicLocked.cpp @@ -24,6 +24,7 @@ #define epicsExportSharedSymbols #include "epicsAtomic.h" +#include "epicsThread.h" #include "epicsMutex.h" namespace { @@ -33,23 +34,47 @@ public: AtomicGuard (); ~AtomicGuard (); private: - static epicsMutexOSD & m_mutex; + static epicsMutexOSD * m_pMutex; + static epicsThreadOnceId m_onceFlag; + static void m_once ( void * ); }; // -// see c++ FAQ, static init order fiasco +// c++ 0x specifies the behavior for concurrent +// access to block scope statics but some compiler +// writers, lacking clear guidance in the earlier +// c++ standards, curiously implement thread unsafe +// block static variables despite ensuring for +// proper multithreaded behavior for many other +// parst of the compiler infrastructure such as +// runtime support for exception handling // -epicsMutexOSD & AtomicGuard :: m_mutex = * epicsMutexOsdCreate (); +// since this is potentially used by the implementation +// of staticInstance we cant use it here and must use +// epicsThreadOnce despite its perfomance pentalty +// +// using epicsThreadOnce here (at this time) increases +// the overhead of AtomicGuard by as much as 100% +// +epicsMutexOSD * AtomicGuard :: m_pMutex = 0; +epicsThreadOnceId AtomicGuard :: m_onceFlag = EPICS_THREAD_ONCE_INIT; + +void AtomicGuard :: m_once ( void * ) +{ + m_pMutex = epicsMutexOsdCreate (); +} inline AtomicGuard :: AtomicGuard () { - const int status = epicsMutexOsdLock ( & m_mutex ); + + epicsThreadOnce ( & m_onceFlag, m_once, 0 ); + const int status = epicsMutexOsdLock ( m_pMutex ); assert ( status == epicsMutexLockOK ); } inline AtomicGuard :: ~AtomicGuard () { - epicsMutexOsdUnlock ( & m_mutex ); + epicsMutexOsdUnlock ( m_pMutex ); } } // end of anonymous namespace @@ -92,14 +117,26 @@ unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) return *pTarget; } -unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ) +unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldval, unsigned newval ) { AtomicGuard atomicGuard; - const bool weWillSetIt = ( *pTarget == 0u ); - if ( weWillSetIt ) { - *pTarget = 1u; + const unsigned cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; } - return weWillSetIt; + return cur; +} + +EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) +{ + AtomicGuard atomicGuard; + const EpicsAtomicPtrT cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + return cur; } } // end of extern "C" diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h index 1ca29fd4c..4f9749781 100644 --- a/src/libCom/osi/epicsAtomicLocked.h +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -22,16 +22,6 @@ extern "C" { #endif /* __cplusplus */ -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) -{ - return epicsLockedTestAndSetUIntT ( pTarget ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) -{ - epicsLockedSetUIntT ( pTarget, newVal ); -} - OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { return epicsLockedIncrSizeT ( pTarget ); @@ -57,6 +47,33 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) return epicsLockedGetUIntT ( pTarget ); } +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + epicsLockedSetUIntT ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + epicsLockedSetPtrT ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + return epicsLockedGetPtrT ( pTarget ); +} + +OSD_ATOMIC_INLINE unsigned epicsAomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) +{ + return epicsLockedCmpAndSwapUIntT ( pTarget, oldVal, newVal ); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) +{ + return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ @@ -67,9 +84,12 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) # define epicsAtomicDecrSizeT epicsLockedDecrSizeT # define epicsAtomicSetSizeT epicsLockedSetSizeT # define epicsAtomicSetUIntT epicsLockedSetUIntT +# define epicsAtomicSetPtrT epicsLockedSetPtrT # define epicsAtomicGetSizeT epicsLockedGetSizeT # define epicsAtomicGetUIntT epicsLockedGetUIntT -# define epicsAtomicTestAndSetUIntT epicsLockedTestAndSetUIntT +# define epicsAtomicGetPtrT epicsLockedGetPtrT +# define epicsAtomicCmpAndSwapUIntT epicsLockedCmpAndSwapUIntT +# define epicsAtomicCmpAndSwapPtrT epicsLockedCmpAndSwapPtrT #endif /* if defined ( OSD_ATOMIC_INLINE ) */ diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index 27b59b242..3b3ab6942 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -20,9 +20,6 @@ #include -#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ -#include - #include "epicsAssert.h" #define STRICT @@ -33,37 +30,70 @@ extern "C" { #endif /* __cplusplus */ +/* + * mingw doesnt currently provide MemoryBarrier + * (this is mostly for testing purposes as the gnu + * intrinsics are used if compiling for 486 or better + * minimum hardware) + */ +#ifdef __MINGW32__ + extern inline void MemoryBarrier() { + int fence = 0; + __asm__ __volatile__( "xchgl %%eax,%0 ":"=r" (fence) ); + } +#endif // ifdef __MINGW32__ + /* necessary for next three functions */ STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) ); OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) { - LONG * const pTarg = ( LONG * ) ( pTarget ); - InterlockedExchange ( pTarg, ( LONG ) newVal ); + *pTarget = newVal; + MemoryBarrier (); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + *pTarget = newVal; + MemoryBarrier (); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + *pTarget = newVal; + MemoryBarrier (); } OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { - LONG * const pTarg = ( LONG * ) ( pTarget ); - return InterlockedExchangeAdd ( pTarg, 0 ); + MemoryBarrier (); + return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - long * const pTarg = ( LONG * ) ( pTarget ); - return InterlockedCompareExchange ( pTarg, 1, 0 ) == 0; + MemoryBarrier (); + return *pTarget; } -/* - * on win32 a LONG is 32 bits, but I am concerned that - * we shouldnt use LONG_MAX here because with certain - * compilers a long will be 64 bits wide - */ -#define WIN32_LONG_MAX 0xffffffff -#if SIZE_MAX == WIN32_LONG_MAX +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + MemoryBarrier (); + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + return (unsigned) InterlockedCompareExchange ( pTarg, + (LONG) newVal, (LONG) oldVal ); +} + +#if defined ( _WIN32 ) /* - * necessary for next four functions + * necessary for next five functions * * looking at the MS documentation it appears that they will * keep type long the same size as an int on 64 bit builds @@ -82,22 +112,18 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) return InterlockedDecrement ( pTarg ); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { LONG * const pTarg = ( LONG * ) ( pTarget ); - InterlockedExchange ( pTarg, ( LONG ) newVal ); + return (EpicsAtomicPtrT) InterlockedCompareExchange ( pTarg, + (LONG) newVal, (LONG) oldVal ); } -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - LONG * const pTarg = ( LONG * ) ( pTarget ); - return InterlockedExchangeAdd ( pTarg, 0 ); -} - -#else /* SIZE_MAX == WIN32_LONG_MAX */ +#elif defined ( _WIN64 ) /* - * necessary for next four functions + * necessary for next five functions */ STATIC_ASSERT ( sizeof ( LONGLONG ) == sizeof ( size_t ) ); @@ -113,19 +139,15 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) return InterlockedDecrement64 ( pTarg ); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); - InterlockedExchange64 ( pTarg, ( LONGLONG ) newVal ); + return (EpicsAtomicPtrT) InterlockedCompareExchange64 ( pTarg, + (LONGLONG) newVal, (LONGLONG) oldVal ); } -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); - return InterlockedExchangeAdd64 ( pTarg, 0 ); -} - -#endif /* SIZE_MAX == WIN32_LONG_MAX */ +#endif /* if defined ( _WIN32 ) */ #ifdef __cplusplus } /* end of extern "C" */ diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 7a6946899..542997ccf 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -33,91 +33,66 @@ extern "C" { #endif /* __cplusplus */ -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) { - const uint_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u ); - return oldVal == 0u; + return atomic_cas_uint ( pTarget, oldVal, newVal ); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + return atomic_cas_ptr ( pTarget, oldVal, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + void * const pTarg = ( void * ) ( pTarget ); + return ( size_t ) atomic_inc_ptr_nv ( pTarg ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + void * const pTarg = ( void * ) ( pTarget ); + return atomic_dec_ptr_nv ( pTarg ); } OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) { - atomic_swap_uint ( pTarget, newVal ); + *pTarget = newVal; + membar_producer(); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + *pTarget = newVal; + membar_producer(); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + *pTarget = newVal; + membar_producer(); } OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { - /* - * we cast away const, but are careful not to modify - * the target - */ - unsigned * const pTarg = ( unsigned * ) ( pTarget ); - return atomic_or_uint_nv ( pTarg, 0U ); -} - -#if SIZE_MAX == UINT_MAX - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - unsigned * const pTarg = ( unsigned * ) ( pTarget ); - return atomic_inc_uint_nv ( pTarg ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - unsigned * const pTarg = ( unsigned * ) ( pTarget ); - return atomic_dec_uint_nv ( pTarg ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - unsigned * const pTarg = ( unsigned * ) ( pTarget ); - atomic_swap_uint ( pTarg, newVal ); + membar_consumer (); + return *pTarget; } OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - /* - * we cast away const, but are careful not to modify - * the target - */ - unsigned * const pTarg = ( unsigned * ) ( pTarget ); - return atomic_or_uint_nv ( pTarg, 0U ); + membar_consumer (); + return *pTarget; } -#elif SIZE_MAX == ULONG_MAX - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) { - unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); - return atomic_inc_ulong_nv ( pTarg ); + membar_consumer (); + return *pTarget; } -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); - return atomic_dec_ulong_nv ( pTarg ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); - atomic_swap_ulong ( pTarg, newVal ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - /* - * we cast away const, but are careful not to modify - * the target - */ - unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); - return atomic_or_ulong_nv ( pTarg, 0UL ); -} - -#else -# error unsupported solaris architecture -#endif /* SIZE_MAX == UINT_MAX */ - #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 76ecf0c84..e71f6d9b6 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -75,13 +75,32 @@ OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) vxAtomicSet ( pTarg, newVal ); } +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + vxAtomicSet ( pTarg, newVal ); +} + OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); return ( size_t ) vxAtomicGet ( pTarg ); } -#else /* SIZE_MAX == UINT_MAX */ +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return ( EpicsAtomicPtrT ) vxAtomicGet ( pTarg ); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return (EpicsAtomicPtrT) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); +} + +#else /* ULONG_MAX == UINT_MAX */ /* * if its 64 bit vxWorks and the compiler doesnt @@ -104,12 +123,28 @@ OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) epicsLockedSetSizeT ( pTarget, newVal ); } +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + epicsLockedSetPtrT ( pTarget, newVal ); +} + OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { return epicsLockedGetSizeT ( pTarget ); } -#endif /* SIZE_MAX == UINT_MAX */ +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + return epicsLockedGetPtrT ( pTarget ); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); +} + +#endif /* ULONG_MAX == UINT_MAX */ STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); @@ -119,13 +154,6 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal vxAtomicSet ( pTarg, newVal ); } -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) -{ - STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); - atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return vxCas ( pTarg, 0, 1 ) != 0; -} - OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); @@ -133,6 +161,13 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) return ( unsigned ) vxAtomicGet ( pTarg ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return (unsigned) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ @@ -196,6 +231,15 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal *pTarget = newVal; } +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + *pTarget = newVal; +} + OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { /* @@ -214,10 +258,51 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) { - STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); - return vxTas ( pTarget ); + /* + * no need for memory barrior since this + * is a single cpu system + */ + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + * + * !!!! beware, this will not guarantee an atomic operation + * !!!! if the target operand is on the VME bus + */ + const int key = intLock (); + const unsigned curr = *pTarget; + if ( curr == oldVal ) { + *pTarget = newVal; + } + intUnlock ( key ); + return curr; +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + * + * !!!! beware, this will not guarantee an atomic operation + * !!!! if the target operand is on the VME bus + */ + const int key = intLock (); + const EpicsAtomicPtrT curr = *pTarget; + if ( curr == oldVal ) { + *pTarget = newVal; + } + intUnlock ( key ); + return curr; } #ifdef __cplusplus diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp index 5a8307598..3a116008d 100644 --- a/src/libCom/test/epicsAtomicPerform.cpp +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -305,46 +305,46 @@ inline void oneThousandAtomicIncr ( size_t & target ) oneHundredAtomicIncr ( target ); } -inline void tenAtomicTestAndSet ( unsigned & target ) +inline void tenAtomicCmpAndSwap ( unsigned & target ) { - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); } -inline void oneHundredAtomicTestAndSet ( unsigned & target ) +inline void oneHundredAtomicCmpAndSwap ( unsigned & target ) { - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); } -inline void oneThousandAtomicTestAndSet ( unsigned & target ) +inline void oneThousandAtomicCmpAndSwap ( unsigned & target ) { - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); } inline void tenAtomicSet ( size_t & target ) @@ -421,20 +421,20 @@ void epicsAtomicIncrPerformance () testDiag ( "epicsAtomicIncr() takes %f microseconds", delay ); } -void atomicTestAndSetPerformance () +void atomicCmpAndSwapPerformance () { epicsTime begin = epicsTime::getCurrent (); unsigned target; epicsAtomicSetUIntT ( & target, 0 ); testOk1 ( ! target ); for ( unsigned i = 0; i < N; i++ ) { - oneThousandAtomicTestAndSet ( target ); + oneThousandAtomicCmpAndSwap ( target ); } double delay = epicsTime::getCurrent () - begin; testOk1 ( target ); delay /= N * 1000u; // convert to delay per call delay *= 1e6; // convert to micro seconds - testDiag ( "epicsAtomicCompareAndSet() takes %f microseconds", delay ); + testDiag ( "epicsAtomicCmpAndSwap() takes %f microseconds", delay ); } void recursiveOwnershipRetPerformance () @@ -494,6 +494,6 @@ MAIN(epicsAtomicPerform) epicsAtomicIncrPerformance (); recursiveOwnershipRetPerformance (); ownershipPassRefPerformance (); - atomicCompareAndSetPerformance (); + atomicCmpAndSwapPerformance (); return testDone(); } diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index 5e0760b44..79f90f6d5 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -27,94 +27,147 @@ static void decr ( void *arg ) epicsAtomicIncrSizeT ( & pTestData->m_testIterations ); } -typedef struct TestDataTNS { +typedef struct TestDataTNS_UIntT { unsigned m_testValue; size_t m_testIterationsSet; size_t m_testIterationsNotSet; -} TestDataTNS; +} TestDataTNS_UIntT; + +typedef struct TestDataTNS_PtrT { + EpicsAtomicPtrT m_testValue; + size_t m_testIterationsSet; + size_t m_testIterationsNotSet; +} TestDataTNS_PtrT; + int isModulo ( size_t N, size_t n ) { return ( n % N ) == 0u; } -static void tns ( void *arg ) +static void tns_UIntT ( void *arg ) { - TestDataTNS * const pTestData = (TestDataTNS *) arg; + TestDataTNS_UIntT * const pTestData = (TestDataTNS_UIntT *) arg; /* * intentionally waste cpu and maximize * contention for the shared data */ epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); - while ( ! epicsAtomicTestAndSetUIntT ( & pTestData->m_testValue ) ) { + while ( ! epicsAtomicCmpAndSwapUIntT ( & pTestData->m_testValue, 0u, 1u ) ) { } - testOk ( epicsAtomicGetUIntT ( & pTestData->m_testValue ), - "test and set must leave operand in true state" ); epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u ); epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); } -MAIN(epicsAtomicTest) +static void tns_PtrT ( void *arg ) +{ + static char dummy = 0; + TestDataTNS_PtrT * const pTestData = (TestDataTNS_PtrT *) arg; + /* + * intentionally waste cpu and maximize + * contention for the shared data + */ + epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); + while ( ! epicsAtomicCmpAndSwapPtrT ( & pTestData->m_testValue, 0, & dummy ) ) { + } + epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); + epicsAtomicSetPtrT ( & pTestData->m_testValue, 0u ); + epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); +} + +MAIN(osiAtomicTest) { const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); - static const size_t N_incrDecr = 100; - static const size_t N_testAndSet = 10; - - testPlan( 9 + N_testAndSet ); + testPlan(14); { - + static const size_t N = 100; size_t i; - TestDataIncrDecr testData = { 0, N_incrDecr }; - epicsAtomicSetSizeT ( & testData.m_testValue, N_incrDecr ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr, + TestDataIncrDecr testData = { 0, N };; + epicsAtomicSetSizeT ( & testData.m_testValue, N ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, "set/get %u", testData.m_testValue ); epicsAtomicSetSizeT ( & testData.m_testIterations, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 0u, "set/get %u", testData.m_testIterations ); - for ( i = 0u; i < N_incrDecr; i++ ) { - epicsThreadCreate ( "incr", 50, stackSize, incr, & testData ); - epicsThreadCreate ( "decr", 50, stackSize, decr, & testData ); + for ( i = 0u; i < N; i++ ) { + epicsThreadCreate ( "incr", + 50, stackSize, incr, & testData ); + epicsThreadCreate ( "decr", + 50, stackSize, decr, & testData ); } - while ( testData.m_testIterations < 2 * N_incrDecr ) { + while ( testData.m_testIterations < 2 * N ) { epicsThreadSleep ( 0.01 ); } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N_incrDecr, - "incr/decr iterations %u", testData.m_testIterations ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr, - "incr/decr final value %u", testData.m_testValue ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N, + "incr/decr iterations %u", + testData.m_testIterations ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, + "incr/decr final value %u", + testData.m_testValue ); } { + static const unsigned initVal = 1; + static const size_t N = 10; size_t i; - TestDataTNS testData = { 1, N_testAndSet, N_testAndSet }; + TestDataTNS_UIntT testData = { 0, N, N }; epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, "set/get %u", testData.m_testIterationsSet ); epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, "set/get %u", testData.m_testIterationsNotSet ); - for ( i = 0u; i < N_testAndSet; i++ ) { + epicsAtomicSetUIntT ( & testData.m_testValue, initVal ); + testOk ( epicsAtomicGetUIntT ( & testData.m_testValue ) == initVal, + "PtrT set/get %u", testData.m_testValue ); + for ( i = 0u; i < N; i++ ) { epicsThreadCreate ( "tns", - 50, stackSize, tns, & testData ); + 50, stackSize, tns_UIntT, & testData ); } epicsAtomicSetUIntT ( & testData.m_testValue, 0u ); - while ( testData.m_testIterationsSet < N_testAndSet ) { + while ( testData.m_testIterationsSet < N ) { epicsThreadSleep ( 0.01 ); } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N_testAndSet, - "test and set iterations %u", testData.m_testIterationsSet ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, + "test and set iterations %u", + testData.m_testIterationsSet ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "test and set not-set tracking = %u", testData.m_testIterationsNotSet ); + "test and set not-set tracking = %u", + testData.m_testIterationsNotSet ); + } + { - static unsigned setVal = 5; - epicsAtomicSetUIntT ( & testData.m_testValue, setVal ); - testOk ( epicsAtomicGetUIntT ( & testData.m_testValue ) == setVal, - "unsigned version of set and get must concur" ); + static const size_t N = 10; + static char dummy; + size_t i; + TestDataTNS_PtrT testData = { 0, N, N }; + epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, + "set/get %u", testData.m_testIterationsSet ); + epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, + "SizeT set/get %u", testData.m_testIterationsNotSet ); + epicsAtomicSetPtrT ( & testData.m_testValue, & dummy ); + testOk ( epicsAtomicGetPtrT ( & testData.m_testValue ) == & dummy, + "PtrT set/get %p", testData.m_testValue ); + for ( i = 0u; i < N; i++ ) { + epicsThreadCreate ( "tns", + 50, stackSize, tns_PtrT, & testData ); } + epicsAtomicSetPtrT ( & testData.m_testValue, 0u ); + while ( testData.m_testIterationsSet < N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, + "test and set iterations %u", + testData.m_testIterationsSet ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, + "test and set not-set tracking = %u", + testData.m_testIterationsNotSet ); } return testDone(); From b9900b86825e745ca0ba49ed995ce24b58142d52 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 15 Aug 2011 17:00:01 -0600 Subject: [PATCH 36/61] o no longer need to define OSD_ATOMIC_GCC o removed function epicsAtomicTestAndSetUIntT o added new functions epicsAtomicSetPtrT epicsAtomicGetPtrT epicsAtomicCmpAndSwapUIntT epicsAtomicCmpAndSwapPtrT o changed msvc intrinsics to define memory fence o fixed mutex synchronized version so that its slow, but correct if the c++ compiler doesnt synchronized local scope static initialization o changed most of the set/get methods to use memory barriers instead of some other primitive o added additional tests --- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 37 +++++- src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 112 ++++++++++------- src/libCom/osi/epicsAtomic.h | 32 +++-- src/libCom/osi/epicsAtomicLocked.cpp | 57 +++++++-- src/libCom/osi/epicsAtomicLocked.h | 42 +++++-- src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 96 +++++++++------ src/libCom/osi/os/solaris/epicsAtomicOSD.h | 109 +++++++--------- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 109 ++++++++++++++-- src/libCom/test/epicsAtomicPerform.cpp | 74 +++++------ src/libCom/test/epicsAtomicTest.c | 123 +++++++++++++------ 10 files changed, 525 insertions(+), 266 deletions(-) diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index faf1c7886..8b06bd7bb 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -39,16 +39,17 @@ ( defined ( __i486 ) || defined ( __pentium ) || \ defined ( __pentiumpro ) || defined ( __MMX__ ) ) +#define GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER \ + ( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 ) + #define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \ ( GCC_ATOMIC_INTRINSICS_MIN_X86 && \ - ( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 ) ) + GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER ) #if ( GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER -#define OSD_ATOMIC_GCC - #ifdef __cplusplus extern "C" { #endif @@ -77,6 +78,13 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, __sync_synchronize (); } +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT newValue ) +{ + *pTarget = newValue; + __sync_synchronize (); +} + OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { __sync_synchronize (); @@ -89,10 +97,22 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) { - const size_t prev = __sync_lock_test_and_set ( pTarget, 1u ); - return prev == 0; + __sync_synchronize (); + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) +{ + return __sync_val_compare_and_swap ( pTarget, oldVal, newVal); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + return __sync_val_compare_and_swap ( pTarget, oldVal, newVal); } #ifdef __cplusplus @@ -101,6 +121,11 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) #else /* if GCC_ATOMIC_INTRINSICS_AVAIL */ +# if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER && __i386 + /* 386 hardware is probably rare today even in embedded systems */ +# warning "this code will run much faster if specifying i486 or better" +# endif + /* * not available as gcc intrinsics so we * will employ an os specific inline solution diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index 08cd5ea31..4923664e7 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -24,21 +24,6 @@ #ifdef _MSC_EXTENSIONS -/* - * I have discovered an anomaly in visual c++ where - * the DLL instantiation of an exported inline interface - * does not occur in a c++ code unless "inline" is used. - */ -#if defined ( __cplusplus ) -# define OSD_ATOMIC_INLINE inline -#elif defined ( _MSC_VER ) -# define OSD_ATOMIC_INLINE __inline -#endif - -#if defined ( _M_X64 ) || defined ( _M_IA64 ) -# define OSD_ATOMIC_64 -#endif /* defined ( _M_X64 ) || defined ( _M_IA64 ) */ - #include #pragma intrinsic ( _InterlockedExchange ) @@ -54,6 +39,33 @@ # pragma intrinsic ( _InterlockedExchangeAdd64 ) #endif +#if _MSC_VER >= 1200 +# define OSD_ATOMIC_INLINE __forceinline +#else +# define OSD_ATOMIC_INLINE __inline +#endif + +#if defined ( _M_IX86 ) +# pragma warning( push ) +# pragma warning( disable : 4793 ) + OSD_ATOMIC_INLINE void OSD_ATOMIC_SYNC () + { + long fence; + __asm { xchg fence, eax } + } +# pragma warning( pop ) +#elif defined ( _M_X64 ) +# define OSD_ATOMIC_64 +# pragma intrinsic ( __faststorefence ) +# define OSD_ATOMIC_SYNC __faststorefence +#elif defined ( _M_IA64 ) +# define OSD_ATOMIC_64 +# pragma intrinsic ( __mf ) +# define OSD_ATOMIC_SYNC __mf +#else +# error unexpected target architecture, msvc version of epicsAtomicCD.h +#endif + /* * The windows doc appears to recommend defining InterlockedExchange * to be _InterlockedExchange to cause it to be an intrinsic, but that @@ -71,27 +83,53 @@ STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) ); OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) { - long * const pTarg = ( long * ) ( pTarget ); - _InterlockedExchange ( pTarg, ( long ) newVal ); + *pTarget = newVal; + OSD_ATOMIC_SYNC (); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + *pTarget = newVal; + OSD_ATOMIC_SYNC (); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT newVal ) +{ + *pTarget = newVal; + OSD_ATOMIC_SYNC (); } OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { - long * const pTarg = ( long * ) ( pTarget ); - return _InterlockedExchangeAdd ( pTarg, 0 ); + OSD_ATOMIC_SYNC (); + return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + OSD_ATOMIC_SYNC (); + return *pTarget; +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + OSD_ATOMIC_SYNC (); + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) { long * const pTarg = ( long * ) ( pTarget ); - return _InterlockedCompareExchange ( pTarg, 1, 0 ) == 0; + return (unsigned) _InterlockedCompareExchange ( pTarg, + (long) newVal, (long) oldVal ); } - #if ! OSD_ATOMIC_64 /* - * necessary for next four functions + * necessary for next five functions * * looking at the MS documentation it appears that they will * keep type long the same size as an int on 64 bit builds @@ -110,22 +148,18 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) return _InterlockedDecrement ( pTarg ); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { long * const pTarg = ( long * ) ( pTarget ); - _InterlockedExchange ( pTarg, ( long ) newVal ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - long * const pTarg = ( long * ) ( pTarget ); - return _InterlockedExchangeAdd ( pTarg, 0 ); + return (EpicsAtomicPtrT) _InterlockedCompareExchange ( pTarg, + (long) newVal, (long) oldVal ); } #else /* ! OSD_ATOMIC_64 */ /* - * necessary for next four functions + * necessary for next five functions */ STATIC_ASSERT ( sizeof ( long long ) == sizeof ( size_t ) ); @@ -141,16 +175,12 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) return _InterlockedDecrement64 ( pTarg ); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { - long long * const pTarg = ( long long * ) ( pTarget ); - _InterlockedExchange64 ( pTarg, ( long long ) newVal ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - long long * const pTarg = ( long long * ) ( pTarget ); - return _InterlockedExchangeAdd64 ( pTarg, 0 ); + long long * const pTarg = ( longlong * ) ( pTarget ); + return (EpicsAtomicPtrT) _InterlockedCompareExchange64 ( pTarg, + (long long) newVal, (long long) oldVal ); } #endif /* ! OSD_ATOMIC_64 */ diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index 72bb63e54..b444b1240 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -24,6 +24,8 @@ extern "C" { #endif +typedef void * EpicsAtomicPtrT; + /* * lock out other smp processors from accessing the target, * sync target in cache, add one to target, flush target in @@ -53,26 +55,31 @@ epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget ); */ epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue ); epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue ); +epicsShareFunc void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue ); /* * fetch target in cache, return new value of target */ epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget ); epicsShareFunc unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ); +epicsShareFunc EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ); /* * lock out other smp processors from accessing the target, - * sync target in cache, if target is zero set target to - * non-zero (true) value, flush target in cache, allow out - * other smp processors to access the target, return true if - * this request changed the target from a zero value to a - * non-zero (true) value and otherwise false + * sync target in cache, if target is equal to oldVal set target + * to newVal, flush target in cache, allow other smp processors + * to access the target, return the original value stored in the + * target * - * test and set is chosen as the primitive here because, - * compared to comapare-and-swap it is more likely to - * be implemented atomically on old architectures such as 68k + * !!!! beware, this will not guarantee an atomic operation + * !!!! on legacy vxWorks (prior to 6.6) if the target operand + * !!!! is on a multi-commander bus (such as the VME bus) */ -epicsShareFunc unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ); +epicsShareFunc unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ); +epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); + /* * the following are, never inline and always synchronized by a global @@ -84,9 +91,14 @@ epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget ); epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); +epicsShareFunc void epicsLockedSetPtrT ( unsigned * pTarget, EpicsAtomicPtrT newVal ); epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); epicsShareFunc unsigned epicsLockedGetUIntT ( const unsigned * pTarget ); -epicsShareFunc unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ); +epicsShareFunc EpicsAtomicPtrT epicsLockedGetPtrT ( const unsigned * pTarget ); +epicsShareFunc unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldval, unsigned newval ); +epicsShareFunc EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); #ifdef __cplusplus } /* end of extern "C" */ diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp index 625dea118..65a64fb83 100644 --- a/src/libCom/osi/epicsAtomicLocked.cpp +++ b/src/libCom/osi/epicsAtomicLocked.cpp @@ -24,6 +24,7 @@ #define epicsExportSharedSymbols #include "epicsAtomic.h" +#include "epicsThread.h" #include "epicsMutex.h" namespace { @@ -33,23 +34,47 @@ public: AtomicGuard (); ~AtomicGuard (); private: - static epicsMutexOSD & m_mutex; + static epicsMutexOSD * m_pMutex; + static epicsThreadOnceId m_onceFlag; + static void m_once ( void * ); }; // -// see c++ FAQ, static init order fiasco +// c++ 0x specifies the behavior for concurrent +// access to block scope statics but some compiler +// writers, lacking clear guidance in the earlier +// c++ standards, curiously implement thread unsafe +// block static variables despite ensuring for +// proper multithreaded behavior for many other +// parst of the compiler infrastructure such as +// runtime support for exception handling // -epicsMutexOSD & AtomicGuard :: m_mutex = * epicsMutexOsdCreate (); +// since this is potentially used by the implementation +// of staticInstance we cant use it here and must use +// epicsThreadOnce despite its perfomance pentalty +// +// using epicsThreadOnce here (at this time) increases +// the overhead of AtomicGuard by as much as 100% +// +epicsMutexOSD * AtomicGuard :: m_pMutex = 0; +epicsThreadOnceId AtomicGuard :: m_onceFlag = EPICS_THREAD_ONCE_INIT; + +void AtomicGuard :: m_once ( void * ) +{ + m_pMutex = epicsMutexOsdCreate (); +} inline AtomicGuard :: AtomicGuard () { - const int status = epicsMutexOsdLock ( & m_mutex ); + + epicsThreadOnce ( & m_onceFlag, m_once, 0 ); + const int status = epicsMutexOsdLock ( m_pMutex ); assert ( status == epicsMutexLockOK ); } inline AtomicGuard :: ~AtomicGuard () { - epicsMutexOsdUnlock ( & m_mutex ); + epicsMutexOsdUnlock ( m_pMutex ); } } // end of anonymous namespace @@ -92,14 +117,26 @@ unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) return *pTarget; } -unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ) +unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldval, unsigned newval ) { AtomicGuard atomicGuard; - const bool weWillSetIt = ( *pTarget == 0u ); - if ( weWillSetIt ) { - *pTarget = 1u; + const unsigned cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; } - return weWillSetIt; + return cur; +} + +EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) +{ + AtomicGuard atomicGuard; + const EpicsAtomicPtrT cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + return cur; } } // end of extern "C" diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h index 1ca29fd4c..4f9749781 100644 --- a/src/libCom/osi/epicsAtomicLocked.h +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -22,16 +22,6 @@ extern "C" { #endif /* __cplusplus */ -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) -{ - return epicsLockedTestAndSetUIntT ( pTarget ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) -{ - epicsLockedSetUIntT ( pTarget, newVal ); -} - OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { return epicsLockedIncrSizeT ( pTarget ); @@ -57,6 +47,33 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) return epicsLockedGetUIntT ( pTarget ); } +OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +{ + epicsLockedSetUIntT ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + epicsLockedSetPtrT ( pTarget, newVal ); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + return epicsLockedGetPtrT ( pTarget ); +} + +OSD_ATOMIC_INLINE unsigned epicsAomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) +{ + return epicsLockedCmpAndSwapUIntT ( pTarget, oldVal, newVal ); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) +{ + return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ @@ -67,9 +84,12 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) # define epicsAtomicDecrSizeT epicsLockedDecrSizeT # define epicsAtomicSetSizeT epicsLockedSetSizeT # define epicsAtomicSetUIntT epicsLockedSetUIntT +# define epicsAtomicSetPtrT epicsLockedSetPtrT # define epicsAtomicGetSizeT epicsLockedGetSizeT # define epicsAtomicGetUIntT epicsLockedGetUIntT -# define epicsAtomicTestAndSetUIntT epicsLockedTestAndSetUIntT +# define epicsAtomicGetPtrT epicsLockedGetPtrT +# define epicsAtomicCmpAndSwapUIntT epicsLockedCmpAndSwapUIntT +# define epicsAtomicCmpAndSwapPtrT epicsLockedCmpAndSwapPtrT #endif /* if defined ( OSD_ATOMIC_INLINE ) */ diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index 27b59b242..3b3ab6942 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -20,9 +20,6 @@ #include -#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ -#include - #include "epicsAssert.h" #define STRICT @@ -33,37 +30,70 @@ extern "C" { #endif /* __cplusplus */ +/* + * mingw doesnt currently provide MemoryBarrier + * (this is mostly for testing purposes as the gnu + * intrinsics are used if compiling for 486 or better + * minimum hardware) + */ +#ifdef __MINGW32__ + extern inline void MemoryBarrier() { + int fence = 0; + __asm__ __volatile__( "xchgl %%eax,%0 ":"=r" (fence) ); + } +#endif // ifdef __MINGW32__ + /* necessary for next three functions */ STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) ); OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) { - LONG * const pTarg = ( LONG * ) ( pTarget ); - InterlockedExchange ( pTarg, ( LONG ) newVal ); + *pTarget = newVal; + MemoryBarrier (); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + *pTarget = newVal; + MemoryBarrier (); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + *pTarget = newVal; + MemoryBarrier (); } OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { - LONG * const pTarg = ( LONG * ) ( pTarget ); - return InterlockedExchangeAdd ( pTarg, 0 ); + MemoryBarrier (); + return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - long * const pTarg = ( LONG * ) ( pTarget ); - return InterlockedCompareExchange ( pTarg, 1, 0 ) == 0; + MemoryBarrier (); + return *pTarget; } -/* - * on win32 a LONG is 32 bits, but I am concerned that - * we shouldnt use LONG_MAX here because with certain - * compilers a long will be 64 bits wide - */ -#define WIN32_LONG_MAX 0xffffffff -#if SIZE_MAX == WIN32_LONG_MAX +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + MemoryBarrier (); + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + return (unsigned) InterlockedCompareExchange ( pTarg, + (LONG) newVal, (LONG) oldVal ); +} + +#if defined ( _WIN32 ) /* - * necessary for next four functions + * necessary for next five functions * * looking at the MS documentation it appears that they will * keep type long the same size as an int on 64 bit builds @@ -82,22 +112,18 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) return InterlockedDecrement ( pTarg ); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { LONG * const pTarg = ( LONG * ) ( pTarget ); - InterlockedExchange ( pTarg, ( LONG ) newVal ); + return (EpicsAtomicPtrT) InterlockedCompareExchange ( pTarg, + (LONG) newVal, (LONG) oldVal ); } -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - LONG * const pTarg = ( LONG * ) ( pTarget ); - return InterlockedExchangeAdd ( pTarg, 0 ); -} - -#else /* SIZE_MAX == WIN32_LONG_MAX */ +#elif defined ( _WIN64 ) /* - * necessary for next four functions + * necessary for next five functions */ STATIC_ASSERT ( sizeof ( LONGLONG ) == sizeof ( size_t ) ); @@ -113,19 +139,15 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) return InterlockedDecrement64 ( pTarg ); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); - InterlockedExchange64 ( pTarg, ( LONGLONG ) newVal ); + return (EpicsAtomicPtrT) InterlockedCompareExchange64 ( pTarg, + (LONGLONG) newVal, (LONGLONG) oldVal ); } -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); - return InterlockedExchangeAdd64 ( pTarg, 0 ); -} - -#endif /* SIZE_MAX == WIN32_LONG_MAX */ +#endif /* if defined ( _WIN32 ) */ #ifdef __cplusplus } /* end of extern "C" */ diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 7a6946899..542997ccf 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -33,91 +33,66 @@ extern "C" { #endif /* __cplusplus */ -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) { - const uint_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u ); - return oldVal == 0u; + return atomic_cas_uint ( pTarget, oldVal, newVal ); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + return atomic_cas_ptr ( pTarget, oldVal, newVal ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + void * const pTarg = ( void * ) ( pTarget ); + return ( size_t ) atomic_inc_ptr_nv ( pTarg ); +} + +OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + void * const pTarg = ( void * ) ( pTarget ); + return atomic_dec_ptr_nv ( pTarg ); } OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) { - atomic_swap_uint ( pTarget, newVal ); + *pTarget = newVal; + membar_producer(); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + *pTarget = newVal; + membar_producer(); +} + +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + *pTarget = newVal; + membar_producer(); } OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { - /* - * we cast away const, but are careful not to modify - * the target - */ - unsigned * const pTarg = ( unsigned * ) ( pTarget ); - return atomic_or_uint_nv ( pTarg, 0U ); -} - -#if SIZE_MAX == UINT_MAX - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - unsigned * const pTarg = ( unsigned * ) ( pTarget ); - return atomic_inc_uint_nv ( pTarg ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - unsigned * const pTarg = ( unsigned * ) ( pTarget ); - return atomic_dec_uint_nv ( pTarg ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - unsigned * const pTarg = ( unsigned * ) ( pTarget ); - atomic_swap_uint ( pTarg, newVal ); + membar_consumer (); + return *pTarget; } OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - /* - * we cast away const, but are careful not to modify - * the target - */ - unsigned * const pTarg = ( unsigned * ) ( pTarget ); - return atomic_or_uint_nv ( pTarg, 0U ); + membar_consumer (); + return *pTarget; } -#elif SIZE_MAX == ULONG_MAX - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) { - unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); - return atomic_inc_ulong_nv ( pTarg ); + membar_consumer (); + return *pTarget; } -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); - return atomic_dec_ulong_nv ( pTarg ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); - atomic_swap_ulong ( pTarg, newVal ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - /* - * we cast away const, but are careful not to modify - * the target - */ - unsigned long * const pTarg = ( unsigned long * ) ( pTarget ); - return atomic_or_ulong_nv ( pTarg, 0UL ); -} - -#else -# error unsupported solaris architecture -#endif /* SIZE_MAX == UINT_MAX */ - #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 76ecf0c84..e71f6d9b6 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -75,13 +75,32 @@ OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) vxAtomicSet ( pTarg, newVal ); } +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + vxAtomicSet ( pTarg, newVal ); +} + OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); return ( size_t ) vxAtomicGet ( pTarg ); } -#else /* SIZE_MAX == UINT_MAX */ +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return ( EpicsAtomicPtrT ) vxAtomicGet ( pTarg ); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return (EpicsAtomicPtrT) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); +} + +#else /* ULONG_MAX == UINT_MAX */ /* * if its 64 bit vxWorks and the compiler doesnt @@ -104,12 +123,28 @@ OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) epicsLockedSetSizeT ( pTarget, newVal ); } +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + epicsLockedSetPtrT ( pTarget, newVal ); +} + OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { return epicsLockedGetSizeT ( pTarget ); } -#endif /* SIZE_MAX == UINT_MAX */ +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + return epicsLockedGetPtrT ( pTarget ); +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); +} + +#endif /* ULONG_MAX == UINT_MAX */ STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); @@ -119,13 +154,6 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal vxAtomicSet ( pTarg, newVal ); } -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) -{ - STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); - atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return vxCas ( pTarg, 0, 1 ) != 0; -} - OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); @@ -133,6 +161,13 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) return ( unsigned ) vxAtomicGet ( pTarg ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return (unsigned) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ @@ -196,6 +231,15 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal *pTarget = newVal; } +OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + */ + *pTarget = newVal; +} + OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { /* @@ -214,10 +258,51 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) { - STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); - return vxTas ( pTarget ); + /* + * no need for memory barrior since this + * is a single cpu system + */ + return *pTarget; +} + +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldVal, unsigned newVal ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + * + * !!!! beware, this will not guarantee an atomic operation + * !!!! if the target operand is on the VME bus + */ + const int key = intLock (); + const unsigned curr = *pTarget; + if ( curr == oldVal ) { + *pTarget = newVal; + } + intUnlock ( key ); + return curr; +} + +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + /* + * no need for memory barrior since this + * is a single cpu system + * + * !!!! beware, this will not guarantee an atomic operation + * !!!! if the target operand is on the VME bus + */ + const int key = intLock (); + const EpicsAtomicPtrT curr = *pTarget; + if ( curr == oldVal ) { + *pTarget = newVal; + } + intUnlock ( key ); + return curr; } #ifdef __cplusplus diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp index a92d38536..3a116008d 100644 --- a/src/libCom/test/epicsAtomicPerform.cpp +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -305,46 +305,46 @@ inline void oneThousandAtomicIncr ( size_t & target ) oneHundredAtomicIncr ( target ); } -inline void tenAtomicTestAndSet ( unsigned & target ) +inline void tenAtomicCmpAndSwap ( unsigned & target ) { - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); - epicsAtomicTestAndSetUIntT ( & target ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + epicsAtomicCmpAndSwapUIntT ( & target, false, true ); } -inline void oneHundredAtomicTestAndSet ( unsigned & target ) +inline void oneHundredAtomicCmpAndSwap ( unsigned & target ) { - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); - tenAtomicTestAndSet ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); + tenAtomicCmpAndSwap ( target ); } -inline void oneThousandAtomicTestAndSet ( unsigned & target ) +inline void oneThousandAtomicCmpAndSwap ( unsigned & target ) { - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); - oneHundredAtomicTestAndSet ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); + oneHundredAtomicCmpAndSwap ( target ); } inline void tenAtomicSet ( size_t & target ) @@ -421,20 +421,20 @@ void epicsAtomicIncrPerformance () testDiag ( "epicsAtomicIncr() takes %f microseconds", delay ); } -void atomicTestAndSetPerformance () +void atomicCmpAndSwapPerformance () { epicsTime begin = epicsTime::getCurrent (); unsigned target; epicsAtomicSetUIntT ( & target, 0 ); testOk1 ( ! target ); for ( unsigned i = 0; i < N; i++ ) { - oneThousandAtomicTestAndSet ( target ); + oneThousandAtomicCmpAndSwap ( target ); } double delay = epicsTime::getCurrent () - begin; testOk1 ( target ); delay /= N * 1000u; // convert to delay per call delay *= 1e6; // convert to micro seconds - testDiag ( "epicsAtomicCompareAndSet() takes %f microseconds", delay ); + testDiag ( "epicsAtomicCmpAndSwap() takes %f microseconds", delay ); } void recursiveOwnershipRetPerformance () @@ -494,6 +494,6 @@ MAIN(epicsAtomicPerform) epicsAtomicIncrPerformance (); recursiveOwnershipRetPerformance (); ownershipPassRefPerformance (); - atomicTestAndSetPerformance (); + atomicCmpAndSwapPerformance (); return testDone(); } diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index 5e0760b44..79f90f6d5 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -27,94 +27,147 @@ static void decr ( void *arg ) epicsAtomicIncrSizeT ( & pTestData->m_testIterations ); } -typedef struct TestDataTNS { +typedef struct TestDataTNS_UIntT { unsigned m_testValue; size_t m_testIterationsSet; size_t m_testIterationsNotSet; -} TestDataTNS; +} TestDataTNS_UIntT; + +typedef struct TestDataTNS_PtrT { + EpicsAtomicPtrT m_testValue; + size_t m_testIterationsSet; + size_t m_testIterationsNotSet; +} TestDataTNS_PtrT; + int isModulo ( size_t N, size_t n ) { return ( n % N ) == 0u; } -static void tns ( void *arg ) +static void tns_UIntT ( void *arg ) { - TestDataTNS * const pTestData = (TestDataTNS *) arg; + TestDataTNS_UIntT * const pTestData = (TestDataTNS_UIntT *) arg; /* * intentionally waste cpu and maximize * contention for the shared data */ epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); - while ( ! epicsAtomicTestAndSetUIntT ( & pTestData->m_testValue ) ) { + while ( ! epicsAtomicCmpAndSwapUIntT ( & pTestData->m_testValue, 0u, 1u ) ) { } - testOk ( epicsAtomicGetUIntT ( & pTestData->m_testValue ), - "test and set must leave operand in true state" ); epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u ); epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); } -MAIN(epicsAtomicTest) +static void tns_PtrT ( void *arg ) +{ + static char dummy = 0; + TestDataTNS_PtrT * const pTestData = (TestDataTNS_PtrT *) arg; + /* + * intentionally waste cpu and maximize + * contention for the shared data + */ + epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); + while ( ! epicsAtomicCmpAndSwapPtrT ( & pTestData->m_testValue, 0, & dummy ) ) { + } + epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); + epicsAtomicSetPtrT ( & pTestData->m_testValue, 0u ); + epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); +} + +MAIN(osiAtomicTest) { const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); - static const size_t N_incrDecr = 100; - static const size_t N_testAndSet = 10; - - testPlan( 9 + N_testAndSet ); + testPlan(14); { - + static const size_t N = 100; size_t i; - TestDataIncrDecr testData = { 0, N_incrDecr }; - epicsAtomicSetSizeT ( & testData.m_testValue, N_incrDecr ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr, + TestDataIncrDecr testData = { 0, N };; + epicsAtomicSetSizeT ( & testData.m_testValue, N ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, "set/get %u", testData.m_testValue ); epicsAtomicSetSizeT ( & testData.m_testIterations, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 0u, "set/get %u", testData.m_testIterations ); - for ( i = 0u; i < N_incrDecr; i++ ) { - epicsThreadCreate ( "incr", 50, stackSize, incr, & testData ); - epicsThreadCreate ( "decr", 50, stackSize, decr, & testData ); + for ( i = 0u; i < N; i++ ) { + epicsThreadCreate ( "incr", + 50, stackSize, incr, & testData ); + epicsThreadCreate ( "decr", + 50, stackSize, decr, & testData ); } - while ( testData.m_testIterations < 2 * N_incrDecr ) { + while ( testData.m_testIterations < 2 * N ) { epicsThreadSleep ( 0.01 ); } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N_incrDecr, - "incr/decr iterations %u", testData.m_testIterations ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr, - "incr/decr final value %u", testData.m_testValue ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N, + "incr/decr iterations %u", + testData.m_testIterations ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, + "incr/decr final value %u", + testData.m_testValue ); } { + static const unsigned initVal = 1; + static const size_t N = 10; size_t i; - TestDataTNS testData = { 1, N_testAndSet, N_testAndSet }; + TestDataTNS_UIntT testData = { 0, N, N }; epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, "set/get %u", testData.m_testIterationsSet ); epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, "set/get %u", testData.m_testIterationsNotSet ); - for ( i = 0u; i < N_testAndSet; i++ ) { + epicsAtomicSetUIntT ( & testData.m_testValue, initVal ); + testOk ( epicsAtomicGetUIntT ( & testData.m_testValue ) == initVal, + "PtrT set/get %u", testData.m_testValue ); + for ( i = 0u; i < N; i++ ) { epicsThreadCreate ( "tns", - 50, stackSize, tns, & testData ); + 50, stackSize, tns_UIntT, & testData ); } epicsAtomicSetUIntT ( & testData.m_testValue, 0u ); - while ( testData.m_testIterationsSet < N_testAndSet ) { + while ( testData.m_testIterationsSet < N ) { epicsThreadSleep ( 0.01 ); } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N_testAndSet, - "test and set iterations %u", testData.m_testIterationsSet ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, + "test and set iterations %u", + testData.m_testIterationsSet ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "test and set not-set tracking = %u", testData.m_testIterationsNotSet ); + "test and set not-set tracking = %u", + testData.m_testIterationsNotSet ); + } + { - static unsigned setVal = 5; - epicsAtomicSetUIntT ( & testData.m_testValue, setVal ); - testOk ( epicsAtomicGetUIntT ( & testData.m_testValue ) == setVal, - "unsigned version of set and get must concur" ); + static const size_t N = 10; + static char dummy; + size_t i; + TestDataTNS_PtrT testData = { 0, N, N }; + epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, + "set/get %u", testData.m_testIterationsSet ); + epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, + "SizeT set/get %u", testData.m_testIterationsNotSet ); + epicsAtomicSetPtrT ( & testData.m_testValue, & dummy ); + testOk ( epicsAtomicGetPtrT ( & testData.m_testValue ) == & dummy, + "PtrT set/get %p", testData.m_testValue ); + for ( i = 0u; i < N; i++ ) { + epicsThreadCreate ( "tns", + 50, stackSize, tns_PtrT, & testData ); } + epicsAtomicSetPtrT ( & testData.m_testValue, 0u ); + while ( testData.m_testIterationsSet < N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, + "test and set iterations %u", + testData.m_testIterationsSet ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, + "test and set not-set tracking = %u", + testData.m_testIterationsNotSet ); } return testDone(); From e929857ac8a78db0c7172dbaab2d21ebf615b8dc Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 15 Aug 2011 17:59:43 -0600 Subject: [PATCH 37/61] fixed missing missing locked func and broken func proto --- src/libCom/osi/epicsAtomic.h | 4 ++-- src/libCom/osi/epicsAtomicLocked.cpp | 14 +++++++++++++- src/libCom/osi/epicsAtomicLocked.h | 6 +++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index b444b1240..586cb15c2 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -91,10 +91,10 @@ epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget ); epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); -epicsShareFunc void epicsLockedSetPtrT ( unsigned * pTarget, EpicsAtomicPtrT newVal ); +epicsShareFunc void epicsLockedSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ); epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); epicsShareFunc unsigned epicsLockedGetUIntT ( const unsigned * pTarget ); -epicsShareFunc EpicsAtomicPtrT epicsLockedGetPtrT ( const unsigned * pTarget ); +epicsShareFunc EpicsAtomicPtrT epicsLockedGetPtrT ( const EpicsAtomicPtrT * pTarget ); epicsShareFunc unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, unsigned oldval, unsigned newval ); epicsShareFunc EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp index 65a64fb83..42cbb33bd 100644 --- a/src/libCom/osi/epicsAtomicLocked.cpp +++ b/src/libCom/osi/epicsAtomicLocked.cpp @@ -105,13 +105,25 @@ void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ) *pTarget = newVal; } +void epicsLockedSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + AtomicGuard atomicGuard; + *pTarget = newVal; +} + +unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) +{ + AtomicGuard atomicGuard; + return *pTarget; +} + size_t epicsLockedGetSizeT ( const size_t * pTarget ) { AtomicGuard atomicGuard; return *pTarget; } -unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) +EpicsAtomicPtrT epicsLockedGetPtrT ( const EpicsAtomicPtrT * pTarget ) { AtomicGuard atomicGuard; return *pTarget; diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h index 4f9749781..298dcc3dc 100644 --- a/src/libCom/osi/epicsAtomicLocked.h +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -62,14 +62,14 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * p return epicsLockedGetPtrT ( pTarget ); } -OSD_ATOMIC_INLINE unsigned epicsAomicCmpAndSwapUIntT ( unsigned * pTarget, +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, unsigned oldVal, unsigned newVal ) { return epicsLockedCmpAndSwapUIntT ( pTarget, oldVal, newVal ); } -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); } From baaaa3a3134fc59f8ebc725cc76a7ad0438ef0e9 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 15 Aug 2011 17:59:43 -0600 Subject: [PATCH 38/61] fixed missing missing locked func and broken func proto --- src/libCom/osi/epicsAtomic.h | 4 ++-- src/libCom/osi/epicsAtomicLocked.cpp | 14 +++++++++++++- src/libCom/osi/epicsAtomicLocked.h | 6 +++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index b444b1240..586cb15c2 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -91,10 +91,10 @@ epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget ); epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); -epicsShareFunc void epicsLockedSetPtrT ( unsigned * pTarget, EpicsAtomicPtrT newVal ); +epicsShareFunc void epicsLockedSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ); epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); epicsShareFunc unsigned epicsLockedGetUIntT ( const unsigned * pTarget ); -epicsShareFunc EpicsAtomicPtrT epicsLockedGetPtrT ( const unsigned * pTarget ); +epicsShareFunc EpicsAtomicPtrT epicsLockedGetPtrT ( const EpicsAtomicPtrT * pTarget ); epicsShareFunc unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, unsigned oldval, unsigned newval ); epicsShareFunc EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp index 65a64fb83..42cbb33bd 100644 --- a/src/libCom/osi/epicsAtomicLocked.cpp +++ b/src/libCom/osi/epicsAtomicLocked.cpp @@ -105,13 +105,25 @@ void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ) *pTarget = newVal; } +void epicsLockedSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +{ + AtomicGuard atomicGuard; + *pTarget = newVal; +} + +unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) +{ + AtomicGuard atomicGuard; + return *pTarget; +} + size_t epicsLockedGetSizeT ( const size_t * pTarget ) { AtomicGuard atomicGuard; return *pTarget; } -unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) +EpicsAtomicPtrT epicsLockedGetPtrT ( const EpicsAtomicPtrT * pTarget ) { AtomicGuard atomicGuard; return *pTarget; diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h index 4f9749781..298dcc3dc 100644 --- a/src/libCom/osi/epicsAtomicLocked.h +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -62,14 +62,14 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * p return epicsLockedGetPtrT ( pTarget ); } -OSD_ATOMIC_INLINE unsigned epicsAomicCmpAndSwapUIntT ( unsigned * pTarget, +OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, unsigned oldVal, unsigned newVal ) { return epicsLockedCmpAndSwapUIntT ( pTarget, oldVal, newVal ); } -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) +OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); } From b5f1a94fc9badbdf8409d05d669f3cc3b22f1892 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 16 Aug 2011 18:32:41 -0600 Subject: [PATCH 39/61] o cosmetic change CONFIG_COMMON o removed setting of default i586 arch from mingw and cygwin CONFIG_SITE --- configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 | 5 +---- configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin | 3 +-- configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw | 3 --- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 index be2e4a031..dee6a86f0 100644 --- a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 +++ b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 @@ -7,7 +7,4 @@ #------------------------------------------------------- # GNU_DIR used when COMMANDLINE_LIBRARY is READLINE -#GNU_DIR=C:/cygwin - -# default minimum host hardware architecture -#ARCH_DEP_CFLAGS += -march=i586 \ No newline at end of file +#GNU_DIR=C:/cygwin \ No newline at end of file diff --git a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin index 21207d6d6..b28b04f64 100644 --- a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin +++ b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin @@ -1,4 +1,3 @@ -# default minimum host hardware architecture -#ARCH_DEP_CFLAGS += -march=i586 + diff --git a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw index b82efdbc5..771a4ba87 100644 --- a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw @@ -14,6 +14,3 @@ #AR = $(CMPLR_PREFIX)ar -rc #LD = $(CMPLR_PREFIX)ld -r #RANLIB = $(CMPLR_PREFIX)ranlib - -# default minimum host hardware architecture -ARCH_DEP_CFLAGS += -march=i586 \ No newline at end of file From 159ca986a37061cd3d564de4acc6cfdbb29061b1 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 16 Aug 2011 18:32:41 -0600 Subject: [PATCH 40/61] o cosmetic change CONFIG_COMMON o removed setting of default i586 arch from mingw and cygwin CONFIG_SITE --- configure/CONFIG_COMMON | 2 +- configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 | 5 +---- configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin | 3 +-- configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw | 3 --- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/configure/CONFIG_COMMON b/configure/CONFIG_COMMON index d142723a4..fe0353542 100644 --- a/configure/CONFIG_COMMON +++ b/configure/CONFIG_COMMON @@ -140,7 +140,7 @@ ALL_SRC_DIRS = $(CMPLR_SRC_DIRS) $(OS_SRC_DIRS) $(GENERIC_SRC_DIRS) #-------------------------------------------------- # compile line include directories INSTALL_INCLUDES += \ - -I$(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS) \ + -I$(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS) \ -I$(INSTALL_INCLUDE)/os/$(OS_CLASS) \ -I$(INSTALL_INCLUDE) SRC_INCLUDES = -I$(COMMON_DIR) $(addprefix -I, $(wildcard $(ALL_SRC_DIRS))) diff --git a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 index be2e4a031..dee6a86f0 100644 --- a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 +++ b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 @@ -7,7 +7,4 @@ #------------------------------------------------------- # GNU_DIR used when COMMANDLINE_LIBRARY is READLINE -#GNU_DIR=C:/cygwin - -# default minimum host hardware architecture -#ARCH_DEP_CFLAGS += -march=i586 \ No newline at end of file +#GNU_DIR=C:/cygwin \ No newline at end of file diff --git a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin index 21207d6d6..b28b04f64 100644 --- a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin +++ b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin @@ -1,4 +1,3 @@ -# default minimum host hardware architecture -#ARCH_DEP_CFLAGS += -march=i586 + diff --git a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw index b82efdbc5..771a4ba87 100644 --- a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw @@ -14,6 +14,3 @@ #AR = $(CMPLR_PREFIX)ar -rc #LD = $(CMPLR_PREFIX)ld -r #RANLIB = $(CMPLR_PREFIX)ranlib - -# default minimum host hardware architecture -ARCH_DEP_CFLAGS += -march=i586 \ No newline at end of file From 1696c5ea723c482fae9cbab4b88711026d58ad4d Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Wed, 17 Aug 2011 09:05:05 -0600 Subject: [PATCH 41/61] removed lisc file changes From 9b8ee4186031c726db8c26ed9d723fc7d6af69ba Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Wed, 17 Aug 2011 09:05:05 -0600 Subject: [PATCH 42/61] removed lisc file changes --- LICENSE | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/LICENSE b/LICENSE index da661c55f..ff9597ccf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,14 +1,5 @@ -Copyright (c) 2007-2011 UChicago Argonne LLC. All rights reserved. - -Copyright (c) 2006-2011. Los Alamos National Security, LLC. Some of this -material was produced under U.S. Government contract DE-AC52-06NA25396 -for Los Alamos National Laboratory (LANL), which is operated by Los Alamos -National Security, LLC for the U.S. Department of Energy. - -Copyright (c) 1991-2007 the University of Chicago. All rights reserved. - -Copyright (c) 1991-2006 The Regents of the University of California. -All rights reserved. +Copyright (c) 1991-2007 UChicago Argonne LLC and The Regents of the +University of California. All rights reserved. EPICS BASE is distributed subject to the following license conditions: From 8a8ba044055bfb2afe561858ad9a135230b7965e Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 19 Aug 2011 13:48:03 -0600 Subject: [PATCH 43/61] o merged in changes from the "compiler specific build" branch o changed implementation of default mutex locked version to be POSIX specific so we can use a static pthread mutex which is more efficent --- .../os/CONFIG_SITE.cygwin-x86.cygwin-x86 | 3 +- ...FIG_SITE.win32-x86-cygwin.win32-x86-cygwin | 1 - ...ONFIG_SITE.win32-x86-mingw.win32-x86-mingw | 1 + src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 7 +- src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 2 + src/libCom/osi/epicsAtomic.h | 19 --- src/libCom/osi/epicsAtomicGuard.h | 54 +++++++++ src/libCom/osi/epicsAtomicLocked.h | 108 +++++++++++------- src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 2 + src/libCom/osi/os/default/epicsAtomicOSD.cpp | 26 +++++ src/libCom/osi/os/default/epicsAtomicOSD.h | 2 - src/libCom/osi/os/posix/epicsAtomicOSD.cpp | 71 ++++++++++++ src/libCom/osi/os/solaris/epicsAtomicOSD.h | 6 +- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 2 + 14 files changed, 229 insertions(+), 75 deletions(-) create mode 100644 src/libCom/osi/epicsAtomicGuard.h create mode 100644 src/libCom/osi/os/default/epicsAtomicOSD.cpp create mode 100644 src/libCom/osi/os/posix/epicsAtomicOSD.cpp diff --git a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 index dee6a86f0..97e3cb1f3 100644 --- a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 +++ b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 @@ -7,4 +7,5 @@ #------------------------------------------------------- # GNU_DIR used when COMMANDLINE_LIBRARY is READLINE -#GNU_DIR=C:/cygwin \ No newline at end of file +#GNU_DIR=C:/cygwin + diff --git a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin index b28b04f64..139597f9c 100644 --- a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin +++ b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin @@ -1,3 +1,2 @@ - diff --git a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw index 771a4ba87..259d1e0c8 100644 --- a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw @@ -14,3 +14,4 @@ #AR = $(CMPLR_PREFIX)ar -rc #LD = $(CMPLR_PREFIX)ld -r #RANLIB = $(CMPLR_PREFIX)ranlib + diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index 8b06bd7bb..7e961386a 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -50,6 +50,8 @@ && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER +#define OSD_ATOMIC_INLINE_DEFINITION + #ifdef __cplusplus extern "C" { #endif @@ -120,11 +122,6 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * #endif #else /* if GCC_ATOMIC_INTRINSICS_AVAIL */ - -# if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER && __i386 - /* 386 hardware is probably rare today even in embedded systems */ -# warning "this code will run much faster if specifying i486 or better" -# endif /* * not available as gcc intrinsics so we diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index 4923664e7..fa3ba8a81 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -66,6 +66,8 @@ # error unexpected target architecture, msvc version of epicsAtomicCD.h #endif +#define OSD_ATOMIC_INLINE_DEFINITION + /* * The windows doc appears to recommend defining InterlockedExchange * to be _InterlockedExchange to cause it to be an intrinsic, but that diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index 37313a5bb..aa389ea2f 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -80,25 +80,6 @@ epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTa EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); -/* - * the following are, never inline and always synchronized by a global - * mutual exclusion lock, implementations of the epicsAtomicXxxx interface - * which may used to implement the epicsAtomicXxxx functions when - * more efficent primitives aren't available - */ -epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget ); -epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); -epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); -epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); -epicsShareFunc void epicsLockedSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ); -epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); -epicsShareFunc unsigned epicsLockedGetUIntT ( const unsigned * pTarget ); -epicsShareFunc EpicsAtomicPtrT epicsLockedGetPtrT ( const EpicsAtomicPtrT * pTarget ); -epicsShareFunc unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldval, unsigned newval ); -epicsShareFunc EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); - #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/src/libCom/osi/epicsAtomicGuard.h b/src/libCom/osi/epicsAtomicGuard.h new file mode 100644 index 000000000..7e5cf5334 --- /dev/null +++ b/src/libCom/osi/epicsAtomicGuard.h @@ -0,0 +1,54 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomicGuard_h +#define epicsAtomicGuard_h + +// +// This header file is intended only for use with the epicsAtomicLocked +// header file. The intent is that an OS specific implementation of +// epicsAtomicOSD.cpp might first include this file, next implement +// AtomicGuard depending on os specific capabilities, and finally include +// the epicsAtomicLocked header file to define the various epicsAtomicXxxx +// functions. +// +// The AtomicGuard class is defined in a seperate header file +// from the epicsAtomicLocked header for two reasons. +// o First, it must be possible to have an inline definition of the +// AtomicGuard member functions, and that isnt possible if the +// epicsAtomicXxxx function definitions in the epicsAtomicLocked +// header file have already been seen by the translation unit. +// o Second, we need to enforce a uniform interface for all definitions +// of the the AtomicGuard constructor and destructor member functions +// requiring that no exception are thrown. This is because the +// epicsAtomicXxxx functions in the epicsAtomicLocked header file are +// directly callable by C code. +// +// The epicsAtomicXxxx functions in the epicsAtomicLocked do not pass +// any parameters to the AtomicGuard constructor, and therefore the lock +// used by AtomicGuard is restricted to be a global lock for the entire +// multithreaded executable. Therefore, AtomicGuard will typically +// reference some translation unit scope limited global variable in +// the anonymous namespace for implementation of the locking primitive. +// + +namespace { + struct AtomicGuard { + AtomicGuard () throw (); + ~AtomicGuard () throw (); + }; +} // end of anonymous namespace + +#endif // ifndef epicsAtomicGuard_h \ No newline at end of file diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h index 64cad6351..4707d66f9 100644 --- a/src/libCom/osi/epicsAtomicLocked.h +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -11,86 +11,108 @@ * Author Jeffrey O. Hill * johill@lanl.gov */ + +// +// The epicsAtomicXxxxx functions herein are implemented with C++ but directly +// callable by C code, and therefore they must not be instantiated inline. +// Therefore, this isnt a traditional header file because it has function +// definitions that are not inline, and must therefore be included by only +// one module in the executable - typically this is the epicsAtomicOSD +// c++ source file. These out-of-line function definitions are placed in a +// header file so that there is potential code reuse when instantiating for +// a specific OS. An alternative option would have been to place these +// function definitions in a OS type conditionally compiled source file +// but this wasnt done because I suspect that selecting the posix version +// would require a proliferation of "SRCS_XXXX += xxx.cpp" in the libCom +// Makefile for every variety of Unix (a maintenance headache when new +// varieties of UNIX are configured). +// +// Aee also the comments in epicsAtomicGuard header. +// #ifndef epicsAtomicLocked_h #define epicsAtomicLocked_h -#if defined ( OSD_ATOMIC_INLINE ) +#ifndef __cplusplus +# error epicsAtomicLocked.h is intended only for use only by C++ code +#endif + +#include "epicsAtomic.h" // always cross check the function prototypes +#include "epicsAtomicGuard.h" -#ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - return epicsLockedIncrSizeT ( pTarget ); + AtomicGuard atomicGuard; + return ++(*pTarget); } -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - return epicsLockedDecrSizeT ( pTarget ); + AtomicGuard atomicGuard; + return --(*pTarget); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) { - epicsLockedSetSizeT ( pTarget, newVal ); + AtomicGuard atomicGuard; + *pTarget = newVal; } -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) { - return epicsLockedGetSizeT ( pTarget ); + AtomicGuard atomicGuard; + *pTarget = newVal; } -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) { - return epicsLockedGetUIntT ( pTarget ); + AtomicGuard atomicGuard; + *pTarget = newVal; } -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { - epicsLockedSetUIntT ( pTarget, newVal ); + AtomicGuard atomicGuard; + return *pTarget; } -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - epicsLockedSetPtrT ( pTarget, newVal ); + AtomicGuard atomicGuard; + return *pTarget; } -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) { - return epicsLockedGetPtrT ( pTarget ); + AtomicGuard atomicGuard; + return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) +unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldval, unsigned newval ) { - return epicsLockedCmpAndSwapUIntT ( pTarget, oldVal, newVal ); + AtomicGuard atomicGuard; + const unsigned cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + return cur; } -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) { - return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); + AtomicGuard atomicGuard; + const EpicsAtomicPtrT cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + return cur; } -#ifdef __cplusplus -} /* end of extern "C" */ -#endif /* __cplusplus */ - -#else /* if defined ( OSD_ATOMIC_INLINE ) */ - -# define epicsAtomicIncrSizeT epicsLockedIncrSizeT -# define epicsAtomicDecrSizeT epicsLockedDecrSizeT -# define epicsAtomicSetSizeT epicsLockedSetSizeT -# define epicsAtomicSetUIntT epicsLockedSetUIntT -# define epicsAtomicSetPtrT epicsLockedSetPtrT -# define epicsAtomicGetSizeT epicsLockedGetSizeT -# define epicsAtomicGetUIntT epicsLockedGetUIntT -# define epicsAtomicGetPtrT epicsLockedGetPtrT -# define epicsAtomicCmpAndSwapUIntT epicsLockedCmpAndSwapUIntT -# define epicsAtomicCmpAndSwapPtrT epicsLockedCmpAndSwapPtrT - -#endif /* if defined ( OSD_ATOMIC_INLINE ) */ +} // end of extern "C" #endif /* epicsAtomicLocked_h */ diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index 3b3ab6942..bcf48facd 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -30,6 +30,8 @@ extern "C" { #endif /* __cplusplus */ +#define OSD_ATOMIC_INLINE_DEFINITION + /* * mingw doesnt currently provide MemoryBarrier * (this is mostly for testing purposes as the gnu diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.cpp b/src/libCom/osi/os/default/epicsAtomicOSD.cpp new file mode 100644 index 000000000..ecb1ad7c9 --- /dev/null +++ b/src/libCom/osi/os/default/epicsAtomicOSD.cpp @@ -0,0 +1,26 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#define epicsExportSharedSymbols +#include "epicsAtomic.h" + +// +// We need a default epicsAtopmicOSD.cpp which is empty for use when +// a compiler or inline OS specific implementation is provided. See +// "osi/os/posix/epicsAtomicOSD.cpp" for an example OS specific generic +// out-of-line implementation based on a mutex lock. +// +#if ! defined ( OSD_ATOMIC_INLINE_DEFINITION ) +# error the epicsAtomicXxxxx functions definitions are misssing +#endif + diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.h b/src/libCom/osi/os/default/epicsAtomicOSD.h index 0b250495b..bf09ae083 100644 --- a/src/libCom/osi/os/default/epicsAtomicOSD.h +++ b/src/libCom/osi/os/default/epicsAtomicOSD.h @@ -16,6 +16,4 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#include "epicsAtomicLocked.h" - #endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp new file mode 100644 index 000000000..e6cf40d22 --- /dev/null +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp @@ -0,0 +1,71 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + * + * Provide a global mutex version of AtomicGuard on POSIX + * systems for when we dont have more efficent compiler or + * OS primitives intriniscs to use instead. + * + * We implement this mutex-based AtomicGuard primitive directly + * upon the standalone POSIX pthread library so that the epicsAtomic + * library can be used to implement other primitives such + * epicsThreadOnce. + * + * We use a static initialized pthread mutex to minimize code + * size, and are also optimistic that this can be more efficent + * than pthread_once. + */ + +#include + +#define epicsExportSharedSymbols +#include "epicsAtomic.h" + +// If we have an inline implementation then implement +// nothing that conflicts here +#if ! defined ( OSD_ATOMIC_INLINE_DEFINITION ) + +// get the interface for class AtomicGuard +#include "epicsAtomicGuard.h" + +namespace { + +// a statically initialized mutex doesnt need to be destroyed +static pthread_mutex_t AtomicGuard :: mutex = PTHREAD_MUTEX_INITIALIZER; + +inline AtomicGuard :: AtomicGuard () throw () +{ + unsigned countDown = 1000u; + while ( true ) { + status = pthread_mutex_lock ( & mutex ); + if ( status != EINTR ) break; + static const useconds_t retryDelayUSec = 100000; + usleep ( retryDelayUSec ); + countDown--; + assert ( countDown ); + } + assert ( status == 0 ); +} + +inline AtomicGuard :: ~AtomicGuard () throw () +{ + const int status = pthread_mutex_unlock ( & mutex ); + assert ( status == 0 ); +} + +} // end of namespace anonymous + +// Define the epicsAtomicXxxx functions out-of-line using this +// implementation of AtomicGuard. Note that this isnt a traditional +// c++ header file. +#include "epicsAtomicLocked.h" + +#endif // if ! defined ( #define OSD_ATOMIC_INLINE_DEFINITION ) diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 542997ccf..48c95824a 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -29,6 +29,8 @@ #define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ #include +#define OSD_ATOMIC_INLINE_DEFINITION + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -97,10 +99,6 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * p } /* end of extern "C" */ #endif /* __cplusplus */ -#else /* ifdef __SunOS_5_10 */ - -#include "epicsAtomicLocked.h" - #endif /* ifdef __SunOS_5_10 */ #endif /* if defined ( OSD_ATOMIC_INLINE ) */ diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index e71f6d9b6..b46c66436 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -28,6 +28,8 @@ #include #include + +#define OSD_ATOMIC_INLINE_DEFINITION #ifdef __cplusplus extern "C" { From 4d8045ab5abff06821ef3f2bbb8c5709617a566d Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 19 Aug 2011 13:48:03 -0600 Subject: [PATCH 44/61] o merged in changes from the "compiler specific build" branch o changed implementation of default mutex locked version to be POSIX specific so we can use a static pthread mutex which is more efficent --- configure/CONFIG_COMMON | 6 +- configure/RULES_BUILD | 2 +- .../os/CONFIG_SITE.cygwin-x86.cygwin-x86 | 3 +- ...FIG_SITE.win32-x86-cygwin.win32-x86-cygwin | 1 - ...ONFIG_SITE.win32-x86-mingw.win32-x86-mingw | 1 + src/libCom/Makefile | 8 +- src/libCom/misc/compilerDependencies.h | 104 ------------ .../osi/compiler/borland/compilerSpecific.h | 55 ++++++ .../osi/compiler/clang/compilerSpecific.h | 59 +++++++ .../osi/compiler/default/compilerSpecific.h | 45 +++++ .../osi/compiler/gcc/compilerSpecific.h | 59 +++++++ src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 7 +- .../osi/compiler/msvc/compilerSpecific.h | 57 +++++++ src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 2 + src/libCom/osi/compilerDependencies.h | 47 ++++++ src/libCom/osi/epicsAtomic.h | 19 --- src/libCom/osi/epicsAtomicGuard.h | 54 ++++++ src/libCom/osi/epicsAtomicLocked.cpp | 158 ------------------ src/libCom/osi/epicsAtomicLocked.h | 108 +++++++----- src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 2 + src/libCom/osi/os/default/epicsAtomicOSD.cpp | 26 +++ src/libCom/osi/os/default/epicsAtomicOSD.h | 2 - src/libCom/osi/os/posix/epicsAtomicOSD.cpp | 71 ++++++++ src/libCom/osi/os/solaris/epicsAtomicOSD.h | 6 +- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 2 + 25 files changed, 558 insertions(+), 346 deletions(-) delete mode 100644 src/libCom/misc/compilerDependencies.h create mode 100644 src/libCom/osi/compiler/borland/compilerSpecific.h create mode 100644 src/libCom/osi/compiler/clang/compilerSpecific.h create mode 100644 src/libCom/osi/compiler/default/compilerSpecific.h create mode 100644 src/libCom/osi/compiler/gcc/compilerSpecific.h create mode 100644 src/libCom/osi/compiler/msvc/compilerSpecific.h create mode 100644 src/libCom/osi/compilerDependencies.h create mode 100644 src/libCom/osi/epicsAtomicGuard.h delete mode 100644 src/libCom/osi/epicsAtomicLocked.cpp create mode 100644 src/libCom/osi/os/default/epicsAtomicOSD.cpp create mode 100644 src/libCom/osi/os/posix/epicsAtomicOSD.cpp diff --git a/configure/CONFIG_COMMON b/configure/CONFIG_COMMON index fe0353542..72d9d4e9f 100644 --- a/configure/CONFIG_COMMON +++ b/configure/CONFIG_COMMON @@ -382,11 +382,11 @@ INSTALL_PERMISSIONS = 444 # # auto determine the directory paths that things are installed to # RULES: -# 0) found in any one of several compiler specific area +# 0) found in any one of several compiler specific paths # => install to $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS) -# 1) not found in (0) and found in any one of several os specific area +# 1) not found in (0) and found in any one of several OS specific paths # => install to $(INSTALL_INCLUDE)/os/$(OS_CLASS) -# 2) not found in (1) and found in generic area +# 2) not found in (1) and found in generic paths # => install to $(INSTALL_INCLUDE) # 3) not found in (1) or (2) then may be (not yet) computer generated # => install into $(INSTALL_INCLUDE)/os/$(OS_CLASS) and let diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 54ddd9ac4..b861e00e6 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -415,7 +415,7 @@ $(INSTALL_INCLUDE)/% : % @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) $(INSTALL_INCLUDE)/os/$(OS_CLASS)/% : % - $(ECHO) "Installing os dependent include file $@" + $(ECHO) "Installing OS dependent include file $@" @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) $(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS)/% : % diff --git a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 index dee6a86f0..97e3cb1f3 100644 --- a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 +++ b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 @@ -7,4 +7,5 @@ #------------------------------------------------------- # GNU_DIR used when COMMANDLINE_LIBRARY is READLINE -#GNU_DIR=C:/cygwin \ No newline at end of file +#GNU_DIR=C:/cygwin + diff --git a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin index b28b04f64..139597f9c 100644 --- a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin +++ b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin @@ -1,3 +1,2 @@ - diff --git a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw index 771a4ba87..259d1e0c8 100644 --- a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw @@ -14,3 +14,4 @@ #AR = $(CMPLR_PREFIX)ar -rc #LD = $(CMPLR_PREFIX)ld -r #RANLIB = $(CMPLR_PREFIX)ranlib + diff --git a/src/libCom/Makefile b/src/libCom/Makefile index 02efe9348..8ba24f31c 100644 --- a/src/libCom/Makefile +++ b/src/libCom/Makefile @@ -136,7 +136,6 @@ INC += epicsExport.h INC += unixFileName.h INC += locationException.h INC += ipAddrToAsciiAsynchronous.h -INC += compilerDependencies.h INC += epicsUnitTest.h INC += testMain.h SRCS += aToIPAddr.c @@ -185,9 +184,8 @@ INC += osiWireFormat.h INC += osdWireFormat.h INC += osdWireConfig.h INC += epicsAtomic.h -INC += epicsAtomicLocked.h -INC += epicsAtomicOSD.h INC += epicsAtomicCD.h +INC += epicsAtomicOSD.h INC += epicsEndian.h INC += epicsReadline.h INC += epicsMessageQueue.h @@ -199,6 +197,8 @@ INC += devLib.h INC += devLibVME.h INC += devLibVMEImpl.h INC += osdVME.h +INC += compilerDependencies.h +INC += compilerSpecific.h SRCS += epicsThread.cpp SRCS += epicsMutex.cpp @@ -206,7 +206,6 @@ SRCS += epicsEvent.cpp SRCS += epicsTime.cpp SRCS += epicsMessageQueue.cpp SRCS += epicsMath.cpp -SRCS += epicsAtomicLocked.cpp SRCS += epicsAtomicOSD.cpp SRCS += epicsGeneralTime.c @@ -228,7 +227,6 @@ SRCS += epicsTempFile.cpp SRCS += epicsStdio.c SRCS += osdStdio.c - osdEnv_CFLAGS_WIN32= -U__STDC__ SRCS += osdThread.c diff --git a/src/libCom/misc/compilerDependencies.h b/src/libCom/misc/compilerDependencies.h deleted file mode 100644 index 4d451469e..000000000 --- a/src/libCom/misc/compilerDependencies.h +++ /dev/null @@ -1,104 +0,0 @@ - -/*************************************************************************\ -* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* Copyright (c) 2002 The Regents of the University of California, as -* Operator of Los Alamos National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author: - * Jeffrey O. Hill - * johill@lanl.gov - */ - -#ifndef compilerDependencies_h -#define compilerDependencies_h - -/* - * This is an attempt to move all tests identifying what features a - * compiler supports into one file. - * - * Since this is a compiler, and not os dependent, issue then ifdefs - * are used. The ifdefs allow us to make the default assumption that - * standards incompliance issues will be fixed by future compiler - * releases. - */ - -#ifdef __cplusplus - -/* - * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete - * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification - */ - -#if defined ( _MSC_VER ) -# if _MSC_VER >= 1200 /* visual studio 6.0 or later */ -# define CXX_PLACEMENT_DELETE -# endif -# if _MSC_VER > 1300 /* some release after visual studio 7 we hope */ -# define CXX_THROW_SPECIFICATION -# endif -#elif defined ( __HP_aCC ) -# if _HP_aCC > 33300 -# define CXX_PLACEMENT_DELETE -# endif -# define CXX_THROW_SPECIFICATION -#elif defined ( __BORLANDC__ ) -# if __BORLANDC__ >= 0x600 -# define CXX_PLACEMENT_DELETE -# endif -# define CXX_THROW_SPECIFICATION -#elif defined ( __GNUC__ ) -# if __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 95 ) -# define CXX_THROW_SPECIFICATION -# endif -# if __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 96 ) -# define CXX_PLACEMENT_DELETE -# endif -#else -# define CXX_PLACEMENT_DELETE -# define CXX_THROW_SPECIFICATION -#endif - -/* - * usage: void func () epicsThrows (( std::bad_alloc, std::logic_error )) - */ -#if defined ( CXX_THROW_SPECIFICATION ) -# define epicsThrows(X) throw X -#else -# define epicsThrows(X) -#endif - -/* - * usage: epicsPlacementDeleteOperator (( void *, myMemoryManager & )) - */ -#if defined ( CXX_PLACEMENT_DELETE ) -# define epicsPlacementDeleteOperator(X) void operator delete X; -#else -# define epicsPlacementDeleteOperator(X) -#endif - -#endif /* __cplusplus */ - -/* - * Enable format-string checking if possible - */ -#ifdef __GNUC__ -# define EPICS_PRINTF_STYLE(f,a) __attribute__((format(__printf__,f,a))) -#else -# define EPICS_PRINTF_STYLE(f,a) -#endif - -/* - * Deprecation marker - */ -#ifdef __GNUC__ -# define EPICS_DEPRECATED __attribute__((deprecated)) -#else -# define EPICS_DEPRECATED -#endif - -#endif /* ifndef compilerDependencies_h */ diff --git a/src/libCom/osi/compiler/borland/compilerSpecific.h b/src/libCom/osi/compiler/borland/compilerSpecific.h new file mode 100644 index 000000000..9a86e1aae --- /dev/null +++ b/src/libCom/osi/compiler/borland/compilerSpecific.h @@ -0,0 +1,55 @@ + +/*************************************************************************\ +* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author: + * Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef compilerSpecific_h +#define compilerSpecific_h + +#ifndef __BORLANDC__ +# error compiler/borland/compilerSpecific.h is only for use with the Borland compiler +#endif + +#ifdef __cplusplus + +/* + * in general we dont like ifdefs but they do allow us to check the + * compiler version and make the optimistic assumption that + * standards incompliance issues will be fixed by future compiler + * releases + */ + +/* + * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete + * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification + */ +#if __BORLANDC__ >= 0x600 +# define CXX_PLACEMENT_DELETE +#endif + +#define CXX_THROW_SPECIFICATION + +#endif /* __cplusplus */ + +/* + * Enable format-string checking if possible + */ +#define EPICS_PRINTF_STYLE(f,a) + +/* + * Deprecation marker + */ +#define EPICS_DEPRECATED + +#endif /* ifndef compilerSpecific_h */ diff --git a/src/libCom/osi/compiler/clang/compilerSpecific.h b/src/libCom/osi/compiler/clang/compilerSpecific.h new file mode 100644 index 000000000..881c30f42 --- /dev/null +++ b/src/libCom/osi/compiler/clang/compilerSpecific.h @@ -0,0 +1,59 @@ + +/*************************************************************************\ +* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author: + * Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef compilerSpecific_h +#define compilerSpecific_h + +#ifndef __clang__ +# error compiler/clang/compilerSpecific.h is only for use with the clang compiler +#endif + +/* + * WARNING: the current state of this file is only based on reading clang manuals + * and has not actually been tested with the compiler + */ +#pragma warning compiler/clang/compilerSpecific.h is based on reading the manual, but hasnt been tested with the clang compiler + +#ifdef __cplusplus + +/* + * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete + * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification + */ +#define CXX_PLACEMENT_DELETE +#define CXX_THROW_SPECIFICATION + +#endif /* __cplusplus */ + +/* + * Enable format-string checking if possible + */ +#if __has_attribute(format) +# define EPICS_PRINTF_STYLE(f,a) __attribute__((format(__printf__,f,a))) +#else +# define EPICS_PRINTF_STYLE +#endif + +/* + * Deprecation marker if possible + */ +#if __has_attribute(deprecated) +# define EPICS_DEPRECATED __attribute__((deprecated)) +#else +# define EPICS_DEPRECATED +#endif + +#endif /* ifndef compilerSpecific_h */ diff --git a/src/libCom/osi/compiler/default/compilerSpecific.h b/src/libCom/osi/compiler/default/compilerSpecific.h new file mode 100644 index 000000000..da2a21acc --- /dev/null +++ b/src/libCom/osi/compiler/default/compilerSpecific.h @@ -0,0 +1,45 @@ + +/*************************************************************************\ +* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author: + * Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef compilerSpecific_h +#define compilerSpecific_h + +#ifdef __cplusplus + +/* + * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete + * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification + * + * (our default guess is that the compiler implements the C++ 97 standard) + */ +#define CXX_THROW_SPECIFICATION +#define CXX_PLACEMENT_DELETE + +#endif /* __cplusplus */ + +/* + * Enable format-string checking if possible + * (our default guess is that the compiler doesnt implement non-standard extensions) + */ +#define EPICS_PRINTF_STYLE(f,a) + +/* + * Deprecation marker + * (our default guess is that the compiler doesnt implement non-standard extensions) + */ +#define EPICS_DEPRECATED + +#endif /* ifndef compilerSpecific_h */ diff --git a/src/libCom/osi/compiler/gcc/compilerSpecific.h b/src/libCom/osi/compiler/gcc/compilerSpecific.h new file mode 100644 index 000000000..f30b696b5 --- /dev/null +++ b/src/libCom/osi/compiler/gcc/compilerSpecific.h @@ -0,0 +1,59 @@ + +/*************************************************************************\ +* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author: + * Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef compilerSpecific_h +#define compilerSpecific_h + +#ifndef __GNUC__ +# error compiler/gcc/compilerSpecific.h is only for use with the gnu compiler +#endif + +#ifdef __cplusplus + +/* + * in general we dont like ifdefs but they do allow us to check the + * compiler version and make the optimistic assumption that + * standards incompliance issues will be fixed by future compiler + * releases + */ + +/* + * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete + * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification + */ + +#if __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 95 ) +# define CXX_THROW_SPECIFICATION +#endif + +#if __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 96 ) +# define CXX_PLACEMENT_DELETE +#endif + +#endif /* __cplusplus */ + +/* + * Enable format-string checking if possible + */ +#define EPICS_PRINTF_STYLE(f,a) __attribute__((format(__printf__,f,a))) + +/* + * Deprecation marker if possible + */ + +#define EPICS_DEPRECATED __attribute__((deprecated)) + +#endif /* ifndef compilerSpecific_h */ diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index 8b06bd7bb..7e961386a 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -50,6 +50,8 @@ && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER +#define OSD_ATOMIC_INLINE_DEFINITION + #ifdef __cplusplus extern "C" { #endif @@ -120,11 +122,6 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * #endif #else /* if GCC_ATOMIC_INTRINSICS_AVAIL */ - -# if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER && __i386 - /* 386 hardware is probably rare today even in embedded systems */ -# warning "this code will run much faster if specifying i486 or better" -# endif /* * not available as gcc intrinsics so we diff --git a/src/libCom/osi/compiler/msvc/compilerSpecific.h b/src/libCom/osi/compiler/msvc/compilerSpecific.h new file mode 100644 index 000000000..64ebf915f --- /dev/null +++ b/src/libCom/osi/compiler/msvc/compilerSpecific.h @@ -0,0 +1,57 @@ + +/*************************************************************************\ +* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author: + * Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef compilerSpecific_h +#define compilerSpecific_h + +#ifndef _MSC_VER +# error compiler/msvc/compilerSpecific.h is only for use with the Microsoft compiler +#endif + +#ifdef __cplusplus + +/* + * in general we dont like ifdefs but they do allow us to check the + * compiler version and make the optimistic assumption that + * standards incompliance issues will be fixed by future compiler + * releases + */ + +/* + * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete + * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification + */ +#if _MSC_VER >= 1200 /* visual studio 6.0 or later */ +# define CXX_PLACEMENT_DELETE +#endif + +#if _MSC_VER > 1300 /* some release after visual studio 7 we hope */ +# define CXX_THROW_SPECIFICATION +#endif + +#endif /* __cplusplus */ + +/* + * Enable format-string checking if possible + */ +#define EPICS_PRINTF_STYLE(f,a) + +/* + * Deprecation marker + */ +#define EPICS_DEPRECATED + +#endif /* ifndef compilerSpecific_h */ diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index 4923664e7..fa3ba8a81 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -66,6 +66,8 @@ # error unexpected target architecture, msvc version of epicsAtomicCD.h #endif +#define OSD_ATOMIC_INLINE_DEFINITION + /* * The windows doc appears to recommend defining InterlockedExchange * to be _InterlockedExchange to cause it to be an intrinsic, but that diff --git a/src/libCom/osi/compilerDependencies.h b/src/libCom/osi/compilerDependencies.h new file mode 100644 index 000000000..7f2acc699 --- /dev/null +++ b/src/libCom/osi/compilerDependencies.h @@ -0,0 +1,47 @@ + +/*************************************************************************\ +* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author: + * Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef compilerDependencies_h +#define compilerDependencies_h + +#include "compilerSpecific.h" + +#ifdef __cplusplus + +/* + * usage: void func () epicsThrows (( std::bad_alloc, std::logic_error )) + * + * Note: now a widely accepted concensus (ref Meyers and C++ faq) is that + * one should avoid using throw specifications in C++ code + */ +#if defined ( CXX_THROW_SPECIFICATION ) +# define epicsThrows(X) throw X +#else +# define epicsThrows(X) +#endif + +/* + * usage: epicsPlacementDeleteOperator (( void *, myMemoryManager & )) + */ +#if defined ( CXX_PLACEMENT_DELETE ) +# define epicsPlacementDeleteOperator(X) void operator delete X; +#else +# define epicsPlacementDeleteOperator(X) +#endif + +#endif /* __cplusplus */ + +#endif /* ifndef compilerDependencies_h */ diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index 586cb15c2..1a28622bf 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -81,25 +81,6 @@ epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTa EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); -/* - * the following are, never inline and always synchronized by a global - * mutual exclusion lock, implementations of the epicsAtomicXxxx interface - * which may used to implement the epicsAtomicXxxx functions when - * more efficent primitives aren't available - */ -epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget ); -epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); -epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); -epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); -epicsShareFunc void epicsLockedSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ); -epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); -epicsShareFunc unsigned epicsLockedGetUIntT ( const unsigned * pTarget ); -epicsShareFunc EpicsAtomicPtrT epicsLockedGetPtrT ( const EpicsAtomicPtrT * pTarget ); -epicsShareFunc unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldval, unsigned newval ); -epicsShareFunc EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); - #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/src/libCom/osi/epicsAtomicGuard.h b/src/libCom/osi/epicsAtomicGuard.h new file mode 100644 index 000000000..7e5cf5334 --- /dev/null +++ b/src/libCom/osi/epicsAtomicGuard.h @@ -0,0 +1,54 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomicGuard_h +#define epicsAtomicGuard_h + +// +// This header file is intended only for use with the epicsAtomicLocked +// header file. The intent is that an OS specific implementation of +// epicsAtomicOSD.cpp might first include this file, next implement +// AtomicGuard depending on os specific capabilities, and finally include +// the epicsAtomicLocked header file to define the various epicsAtomicXxxx +// functions. +// +// The AtomicGuard class is defined in a seperate header file +// from the epicsAtomicLocked header for two reasons. +// o First, it must be possible to have an inline definition of the +// AtomicGuard member functions, and that isnt possible if the +// epicsAtomicXxxx function definitions in the epicsAtomicLocked +// header file have already been seen by the translation unit. +// o Second, we need to enforce a uniform interface for all definitions +// of the the AtomicGuard constructor and destructor member functions +// requiring that no exception are thrown. This is because the +// epicsAtomicXxxx functions in the epicsAtomicLocked header file are +// directly callable by C code. +// +// The epicsAtomicXxxx functions in the epicsAtomicLocked do not pass +// any parameters to the AtomicGuard constructor, and therefore the lock +// used by AtomicGuard is restricted to be a global lock for the entire +// multithreaded executable. Therefore, AtomicGuard will typically +// reference some translation unit scope limited global variable in +// the anonymous namespace for implementation of the locking primitive. +// + +namespace { + struct AtomicGuard { + AtomicGuard () throw (); + ~AtomicGuard () throw (); + }; +} // end of anonymous namespace + +#endif // ifndef epicsAtomicGuard_h \ No newline at end of file diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp deleted file mode 100644 index 42cbb33bd..000000000 --- a/src/libCom/osi/epicsAtomicLocked.cpp +++ /dev/null @@ -1,158 +0,0 @@ - -/*************************************************************************\ -* Copyright (c) 2011 LANS LLC, as Operator of -* Los Alamos National Laboratory. -* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author Jeffrey O. Hill - * johill@lanl.gov - * - * Provide a global mutex version of the atomic functions for when - * we dont have more efficent OS primitives or compiler intriniscs - * to use instead. - * - * We implement these mutex-based primitives upon the libCom private - * interface epicsMutexOsdXxxx because, in libCom, it is convenient - * to make this a standalone primitive upon which we can implement - * epicsMutex. - */ - -#define epicsExportSharedSymbols -#include "epicsAtomic.h" -#include "epicsThread.h" -#include "epicsMutex.h" - -namespace { - -class AtomicGuard { -public: - AtomicGuard (); - ~AtomicGuard (); -private: - static epicsMutexOSD * m_pMutex; - static epicsThreadOnceId m_onceFlag; - static void m_once ( void * ); -}; - -// -// c++ 0x specifies the behavior for concurrent -// access to block scope statics but some compiler -// writers, lacking clear guidance in the earlier -// c++ standards, curiously implement thread unsafe -// block static variables despite ensuring for -// proper multithreaded behavior for many other -// parst of the compiler infrastructure such as -// runtime support for exception handling -// -// since this is potentially used by the implementation -// of staticInstance we cant use it here and must use -// epicsThreadOnce despite its perfomance pentalty -// -// using epicsThreadOnce here (at this time) increases -// the overhead of AtomicGuard by as much as 100% -// -epicsMutexOSD * AtomicGuard :: m_pMutex = 0; -epicsThreadOnceId AtomicGuard :: m_onceFlag = EPICS_THREAD_ONCE_INIT; - -void AtomicGuard :: m_once ( void * ) -{ - m_pMutex = epicsMutexOsdCreate (); -} - -inline AtomicGuard :: AtomicGuard () -{ - - epicsThreadOnce ( & m_onceFlag, m_once, 0 ); - const int status = epicsMutexOsdLock ( m_pMutex ); - assert ( status == epicsMutexLockOK ); -} - -inline AtomicGuard :: ~AtomicGuard () -{ - epicsMutexOsdUnlock ( m_pMutex ); -} - -} // end of anonymous namespace - -extern "C" { - -size_t epicsLockedIncrSizeT ( size_t * pTarget ) -{ - AtomicGuard atomicGuard; - return ++(*pTarget); -} - -size_t epicsLockedDecrSizeT ( size_t * pTarget ) -{ - AtomicGuard atomicGuard; - return --(*pTarget); -} - -void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ) -{ - AtomicGuard atomicGuard; - *pTarget = newVal; -} - -void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ) -{ - AtomicGuard atomicGuard; - *pTarget = newVal; -} - -void epicsLockedSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - AtomicGuard atomicGuard; - *pTarget = newVal; -} - -unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) -{ - AtomicGuard atomicGuard; - return *pTarget; -} - -size_t epicsLockedGetSizeT ( const size_t * pTarget ) -{ - AtomicGuard atomicGuard; - return *pTarget; -} - -EpicsAtomicPtrT epicsLockedGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - AtomicGuard atomicGuard; - return *pTarget; -} - -unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldval, unsigned newval ) -{ - AtomicGuard atomicGuard; - const unsigned cur = *pTarget; - if ( cur == oldval ) { - *pTarget = newval; - } - return cur; -} - -EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) -{ - AtomicGuard atomicGuard; - const EpicsAtomicPtrT cur = *pTarget; - if ( cur == oldval ) { - *pTarget = newval; - } - return cur; -} - -} // end of extern "C" - - - - diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h index 298dcc3dc..5f325e614 100644 --- a/src/libCom/osi/epicsAtomicLocked.h +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -12,86 +12,108 @@ * Author Jeffrey O. Hill * johill@lanl.gov */ + +// +// The epicsAtomicXxxxx functions herein are implemented with C++ but directly +// callable by C code, and therefore they must not be instantiated inline. +// Therefore, this isnt a traditional header file because it has function +// definitions that are not inline, and must therefore be included by only +// one module in the executable - typically this is the epicsAtomicOSD +// c++ source file. These out-of-line function definitions are placed in a +// header file so that there is potential code reuse when instantiating for +// a specific OS. An alternative option would have been to place these +// function definitions in a OS type conditionally compiled source file +// but this wasnt done because I suspect that selecting the posix version +// would require a proliferation of "SRCS_XXXX += xxx.cpp" in the libCom +// Makefile for every variety of Unix (a maintenance headache when new +// varieties of UNIX are configured). +// +// Aee also the comments in epicsAtomicGuard header. +// #ifndef epicsAtomicLocked_h #define epicsAtomicLocked_h -#if defined ( OSD_ATOMIC_INLINE ) +#ifndef __cplusplus +# error epicsAtomicLocked.h is intended only for use only by C++ code +#endif + +#include "epicsAtomic.h" // always cross check the function prototypes +#include "epicsAtomicGuard.h" -#ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - return epicsLockedIncrSizeT ( pTarget ); + AtomicGuard atomicGuard; + return ++(*pTarget); } -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - return epicsLockedDecrSizeT ( pTarget ); + AtomicGuard atomicGuard; + return --(*pTarget); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) { - epicsLockedSetSizeT ( pTarget, newVal ); + AtomicGuard atomicGuard; + *pTarget = newVal; } -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) { - return epicsLockedGetSizeT ( pTarget ); + AtomicGuard atomicGuard; + *pTarget = newVal; } -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) { - return epicsLockedGetUIntT ( pTarget ); + AtomicGuard atomicGuard; + *pTarget = newVal; } -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { - epicsLockedSetUIntT ( pTarget, newVal ); + AtomicGuard atomicGuard; + return *pTarget; } -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - epicsLockedSetPtrT ( pTarget, newVal ); + AtomicGuard atomicGuard; + return *pTarget; } -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) { - return epicsLockedGetPtrT ( pTarget ); + AtomicGuard atomicGuard; + return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) +unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldval, unsigned newval ) { - return epicsLockedCmpAndSwapUIntT ( pTarget, oldVal, newVal ); + AtomicGuard atomicGuard; + const unsigned cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + return cur; } -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) { - return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); + AtomicGuard atomicGuard; + const EpicsAtomicPtrT cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + return cur; } -#ifdef __cplusplus -} /* end of extern "C" */ -#endif /* __cplusplus */ - -#else /* if defined ( OSD_ATOMIC_INLINE ) */ - -# define epicsAtomicIncrSizeT epicsLockedIncrSizeT -# define epicsAtomicDecrSizeT epicsLockedDecrSizeT -# define epicsAtomicSetSizeT epicsLockedSetSizeT -# define epicsAtomicSetUIntT epicsLockedSetUIntT -# define epicsAtomicSetPtrT epicsLockedSetPtrT -# define epicsAtomicGetSizeT epicsLockedGetSizeT -# define epicsAtomicGetUIntT epicsLockedGetUIntT -# define epicsAtomicGetPtrT epicsLockedGetPtrT -# define epicsAtomicCmpAndSwapUIntT epicsLockedCmpAndSwapUIntT -# define epicsAtomicCmpAndSwapPtrT epicsLockedCmpAndSwapPtrT - -#endif /* if defined ( OSD_ATOMIC_INLINE ) */ +} // end of extern "C" #endif /* epicsAtomicLocked_h */ diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index 3b3ab6942..bcf48facd 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -30,6 +30,8 @@ extern "C" { #endif /* __cplusplus */ +#define OSD_ATOMIC_INLINE_DEFINITION + /* * mingw doesnt currently provide MemoryBarrier * (this is mostly for testing purposes as the gnu diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.cpp b/src/libCom/osi/os/default/epicsAtomicOSD.cpp new file mode 100644 index 000000000..ecb1ad7c9 --- /dev/null +++ b/src/libCom/osi/os/default/epicsAtomicOSD.cpp @@ -0,0 +1,26 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#define epicsExportSharedSymbols +#include "epicsAtomic.h" + +// +// We need a default epicsAtopmicOSD.cpp which is empty for use when +// a compiler or inline OS specific implementation is provided. See +// "osi/os/posix/epicsAtomicOSD.cpp" for an example OS specific generic +// out-of-line implementation based on a mutex lock. +// +#if ! defined ( OSD_ATOMIC_INLINE_DEFINITION ) +# error the epicsAtomicXxxxx functions definitions are misssing +#endif + diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.h b/src/libCom/osi/os/default/epicsAtomicOSD.h index 0b250495b..bf09ae083 100644 --- a/src/libCom/osi/os/default/epicsAtomicOSD.h +++ b/src/libCom/osi/os/default/epicsAtomicOSD.h @@ -16,6 +16,4 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#include "epicsAtomicLocked.h" - #endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp new file mode 100644 index 000000000..e6cf40d22 --- /dev/null +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp @@ -0,0 +1,71 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + * + * Provide a global mutex version of AtomicGuard on POSIX + * systems for when we dont have more efficent compiler or + * OS primitives intriniscs to use instead. + * + * We implement this mutex-based AtomicGuard primitive directly + * upon the standalone POSIX pthread library so that the epicsAtomic + * library can be used to implement other primitives such + * epicsThreadOnce. + * + * We use a static initialized pthread mutex to minimize code + * size, and are also optimistic that this can be more efficent + * than pthread_once. + */ + +#include + +#define epicsExportSharedSymbols +#include "epicsAtomic.h" + +// If we have an inline implementation then implement +// nothing that conflicts here +#if ! defined ( OSD_ATOMIC_INLINE_DEFINITION ) + +// get the interface for class AtomicGuard +#include "epicsAtomicGuard.h" + +namespace { + +// a statically initialized mutex doesnt need to be destroyed +static pthread_mutex_t AtomicGuard :: mutex = PTHREAD_MUTEX_INITIALIZER; + +inline AtomicGuard :: AtomicGuard () throw () +{ + unsigned countDown = 1000u; + while ( true ) { + status = pthread_mutex_lock ( & mutex ); + if ( status != EINTR ) break; + static const useconds_t retryDelayUSec = 100000; + usleep ( retryDelayUSec ); + countDown--; + assert ( countDown ); + } + assert ( status == 0 ); +} + +inline AtomicGuard :: ~AtomicGuard () throw () +{ + const int status = pthread_mutex_unlock ( & mutex ); + assert ( status == 0 ); +} + +} // end of namespace anonymous + +// Define the epicsAtomicXxxx functions out-of-line using this +// implementation of AtomicGuard. Note that this isnt a traditional +// c++ header file. +#include "epicsAtomicLocked.h" + +#endif // if ! defined ( #define OSD_ATOMIC_INLINE_DEFINITION ) diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 542997ccf..48c95824a 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -29,6 +29,8 @@ #define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ #include +#define OSD_ATOMIC_INLINE_DEFINITION + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -97,10 +99,6 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * p } /* end of extern "C" */ #endif /* __cplusplus */ -#else /* ifdef __SunOS_5_10 */ - -#include "epicsAtomicLocked.h" - #endif /* ifdef __SunOS_5_10 */ #endif /* if defined ( OSD_ATOMIC_INLINE ) */ diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index e71f6d9b6..b46c66436 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -28,6 +28,8 @@ #include #include + +#define OSD_ATOMIC_INLINE_DEFINITION #ifdef __cplusplus extern "C" { From e8154577db8c260833f7ab34f7b8c267c6dfc3eb Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 19 Aug 2011 14:17:59 -0600 Subject: [PATCH 45/61] fixed issues in posix and vxWorks specific epicsAtomic found during testing --- src/libCom/osi/epicsAtomicGuard.h | 3 ++- src/libCom/osi/os/posix/epicsAtomicOSD.cpp | 6 +++++- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libCom/osi/epicsAtomicGuard.h b/src/libCom/osi/epicsAtomicGuard.h index 7e5cf5334..b9cf2a74d 100644 --- a/src/libCom/osi/epicsAtomicGuard.h +++ b/src/libCom/osi/epicsAtomicGuard.h @@ -51,4 +51,5 @@ namespace { }; } // end of anonymous namespace -#endif // ifndef epicsAtomicGuard_h \ No newline at end of file +#endif // ifndef epicsAtomicGuard_h + diff --git a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp index e6cf40d22..5e182d748 100644 --- a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp @@ -24,9 +24,12 @@ * than pthread_once. */ +#include #include +#include #define epicsExportSharedSymbols +#include "epicsAssert.h" #include "epicsAtomic.h" // If we have an inline implementation then implement @@ -39,11 +42,12 @@ namespace { // a statically initialized mutex doesnt need to be destroyed -static pthread_mutex_t AtomicGuard :: mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; inline AtomicGuard :: AtomicGuard () throw () { unsigned countDown = 1000u; + int status; while ( true ) { status = pthread_mutex_lock ( & mutex ); if ( status != EINTR ) break; diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index b46c66436..b7a9e0f4b 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -20,6 +20,8 @@ #include "vxWorks.h" /* obtain the version of vxWorks */ #include "epicsAssert.h" +#define OSD_ATOMIC_INLINE_DEFINITION + /* * With vxWorks 6.6 and later we need to use vxAtomicLib * to implement this functionality correctly on SMP systems @@ -29,8 +31,6 @@ #include #include -#define OSD_ATOMIC_INLINE_DEFINITION - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ From f0afcef02e2654f346165162c701d9ede6b3aecd Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 29 Aug 2011 19:02:41 -0600 Subject: [PATCH 46/61] o changed to more generic implementation to reduce the code size o changed name, OSD_ATOMIC_INLINE to EPICS_ATOMIC_INLINE o changed supported data types, unsigned removed and int added (per reveiw at codeathon) o added add/subtract functions (per reveiw at codeathon) o now presuming that __sync_synchronize available all gcc 4 mingw does not provide windows mem barrier) o consolodated on one implemention for Microsoft invarient of cmplr intrinisic or win32 by using macros to config a shared header file o improved doc in epicsAtomic.h o added overloaded c++ interface in namespace epics :: atomic to epicsAtomic.h o added epicsAtomicReadMemoryBarrier and epicsAtomicWriteMemoryBarrier interface to epicsAtomic.h o changed the implementation so that each of the functions can be individually specified for a particular compiler, os, or in the generic implementation (this is accomplished with macros) o modified the functional and performance test so that they are based on templates so we can easily support new data types o modified performance tests to repeat function calls and measure performance using a template --- src/libCom/osi/Makefile | 3 + src/libCom/osi/compiler/clang/epicsAtomicCD.h | 4 +- .../osi/compiler/default/epicsAtomicCD.h | 2 +- src/libCom/osi/compiler/gcc/epicsAtomicCD.h | 152 +++--- src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 177 ++----- .../osi/compiler/solStudio/epicsAtomicCD.h | 4 +- src/libCom/osi/epicsAtomic.h | 197 ++++++-- src/libCom/osi/epicsAtomicDefault.h | 235 ++++++++++ src/libCom/osi/epicsAtomicGuard.h | 55 --- src/libCom/osi/epicsAtomicOSD.cpp | 45 -- src/libCom/osi/os/WIN32/epicsAtomicMS.h | 222 +++++++++ .../os/{default => WIN32}/epicsAtomicOSD.cpp | 12 +- src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 163 ++----- src/libCom/osi/os/posix/epicsAtomicOSD.cpp | 99 ++-- .../os/{default => posix}/epicsAtomicOSD.h | 13 + src/libCom/osi/os/solaris/epicsAtomicOSD.h | 140 ++++-- src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp | 22 + src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 340 ++++++-------- src/libCom/test/Makefile | 4 +- src/libCom/test/epicsAtomicPerform.cpp | 431 +++++++++--------- src/libCom/test/epicsAtomicTest.c | 175 ------- src/libCom/test/epicsAtomicTest.cpp | 238 ++++++++++ 22 files changed, 1606 insertions(+), 1127 deletions(-) create mode 100644 src/libCom/osi/epicsAtomicDefault.h delete mode 100644 src/libCom/osi/epicsAtomicGuard.h delete mode 100644 src/libCom/osi/epicsAtomicOSD.cpp create mode 100644 src/libCom/osi/os/WIN32/epicsAtomicMS.h rename src/libCom/osi/os/{default => WIN32}/epicsAtomicOSD.cpp (56%) rename src/libCom/osi/os/{default => posix}/epicsAtomicOSD.h (61%) create mode 100644 src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp delete mode 100644 src/libCom/test/epicsAtomicTest.c create mode 100644 src/libCom/test/epicsAtomicTest.cpp diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index 2b607de4b..c8809166c 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -45,6 +45,7 @@ INC += osiWireFormat.h INC += osdWireFormat.h INC += osdWireConfig.h INC += epicsAtomic.h +INC += epicsAtomicDefault.h INC += epicsAtomicLocked.h INC += epicsAtomicOSD.h INC += epicsAtomicCD.h @@ -131,6 +132,8 @@ Com_SRCS_vxWorks += logMsgToErrlog.cpp #This forces the vxWorks compatibility stuff to be loaded OBJS_vxWorks = vxComLibrary +INC_WIN32 += epicsAtomicMS.h + Com_SRCS_WIN32 += epicsGetopt.c Com_SRCS_WIN32 += setThreadName.cpp #Com_SRCS_WIN32 += dllmain.cpp diff --git a/src/libCom/osi/compiler/clang/epicsAtomicCD.h b/src/libCom/osi/compiler/clang/epicsAtomicCD.h index fea011561..54465d6f4 100644 --- a/src/libCom/osi/compiler/clang/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/clang/epicsAtomicCD.h @@ -17,9 +17,9 @@ #define epicsAtomicCD_h #if defined ( __cplusplus ) -# define OSD_ATOMIC_INLINE inline +# define EPICS_ATOMIC_INLINE inline #else -# define OSD_ATOMIC_INLINE __inline__ +# define EPICS_ATOMIC_INLINE __inline__ #endif #include "epicsAtomicOSD.h" diff --git a/src/libCom/osi/compiler/default/epicsAtomicCD.h b/src/libCom/osi/compiler/default/epicsAtomicCD.h index 60171e377..d07dfb24f 100644 --- a/src/libCom/osi/compiler/default/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/default/epicsAtomicCD.h @@ -17,7 +17,7 @@ #define epicsAtomicCD_h #if __STDC_VERSION__ >= 199901L || defined ( __cplusplus ) -# define OSD_ATOMIC_INLINE inline +# define EPICS_ATOMIC_INLINE inline #endif #include "epicsAtomicOSD.h" diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index 7e961386a..055d8be52 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -20,12 +20,12 @@ # error this header is only for use with the gnu compiler #endif -#define OSD_ATOMIC_INLINE __inline__ +#define EPICS_ATOMIC_INLINE __inline__ #define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B) #define GCC_ATOMIC_CONCATR( A, B ) ( A ## B ) -#define GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ +#define GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \ GCC_ATOMIC_CONCAT ( \ __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \ __SIZEOF_INT__ ) @@ -46,89 +46,127 @@ ( GCC_ATOMIC_INTRINSICS_MIN_X86 && \ GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER ) -#if ( GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ - && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ - || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER - -#define OSD_ATOMIC_INLINE_DEFINITION - #ifdef __cplusplus extern "C" { #endif -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - return __sync_add_and_fetch ( pTarget, 1u ); -} +/* + * We are optimistic that __sync_synchronize is implemented + * in all version four gcc invarient of target. The gnu doc + * seems to say that when not supported by architecture a call + * to an external function is generated but in practice + * this isnt the case for some of the atomic intrinsics, and + * so there is an undefined symbol. So far we have not seen + * that with __sync_synchronize, but we can only guess based + * on experimental evidence. + * + * For example we know that when generating object code for + * 386 most of the atomic instrinsics are not present and + * we see undefined symbols with mingw, but we dont have + * troubles with __sync_synchronize. + */ +#if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - return __sync_sub_and_fetch ( pTarget, 1u ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, - size_t newValue ) -{ - *pTarget = newValue; - __sync_synchronize (); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, - unsigned newValue ) -{ - *pTarget = newValue; - __sync_synchronize (); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT newValue ) -{ - *pTarget = newValue; - __sync_synchronize (); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER +#define EPICS_ATOMIC_READ_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () { __sync_synchronize (); - return *pTarget; } +#endif -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER +#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () { __sync_synchronize (); - return *pTarget; } +#endif -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +#endif /* if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER */ + +#if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \ + || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER + +#define EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) { - __sync_synchronize (); - return *pTarget; + return __sync_add_and_fetch ( pTarget, 1 ); } -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) +#define EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) +{ + return __sync_sub_and_fetch ( pTarget, 1 ); +} + +#define EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) +{ + return __sync_add_and_fetch ( pTarget, delta ); +} + +#define EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ) { return __sync_val_compare_and_swap ( pTarget, oldVal, newVal); } -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, +#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T */ + +#if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \ + || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER + +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return __sync_add_and_fetch ( pTarget, 1u ); +} + +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return __sync_sub_and_fetch ( pTarget, 1u ); +} + +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) +{ + return __sync_add_and_fetch ( pTarget, delta ); +} + +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) +{ + return __sync_sub_and_fetch ( pTarget, delta ); +} + +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldVal, size_t newVal ) +{ + return __sync_val_compare_and_swap ( pTarget, oldVal, newVal); +} + +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { return __sync_val_compare_and_swap ( pTarget, oldVal, newVal); } +#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T */ + #ifdef __cplusplus } /* end of extern "C" */ #endif -#else /* if GCC_ATOMIC_INTRINSICS_AVAIL */ - - /* - * not available as gcc intrinsics so we - * will employ an os specific inline solution - */ -# include "epicsAtomicOSD.h" - -#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL */ +/* + * if currently unavailable as gcc intrinsics we + * will try for an os specific inline solution + */ +#include "epicsAtomicOSD.h" #endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index fa3ba8a81..ca9295f73 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -26,178 +26,99 @@ #include -#pragma intrinsic ( _InterlockedExchange ) -#pragma intrinsic ( _InterlockedCompareExchange ) -#pragma intrinsic ( _InterlockedIncrement ) -#pragma intrinsic ( _InterlockedDecrement ) -#pragma intrinsic ( _InterlockedExchange ) -#pragma intrinsic ( _InterlockedExchangeAdd ) -#if OSD_ATOMIC_64 -# pragma intrinsic ( _InterlockedIncrement64 ) -# pragma intrinsic ( _InterlockedDecrement64 ) -# pragma intrinsic ( _InterlockedExchange64 ) -# pragma intrinsic ( _InterlockedExchangeAdd64 ) -#endif - #if _MSC_VER >= 1200 -# define OSD_ATOMIC_INLINE __forceinline +# define EPICS_ATOMIC_INLINE __forceinline #else -# define OSD_ATOMIC_INLINE __inline +# define EPICS_ATOMIC_INLINE __inline #endif #if defined ( _M_IX86 ) # pragma warning( push ) # pragma warning( disable : 4793 ) - OSD_ATOMIC_INLINE void OSD_ATOMIC_SYNC () + EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier () { long fence; __asm { xchg fence, eax } } # pragma warning( pop ) #elif defined ( _M_X64 ) -# define OSD_ATOMIC_64 +# define MS_ATOMIC_64 # pragma intrinsic ( __faststorefence ) -# define OSD_ATOMIC_SYNC __faststorefence + EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier () + { + __faststorefence (); + } #elif defined ( _M_IA64 ) -# define OSD_ATOMIC_64 +# define MS_ATOMIC_64 # pragma intrinsic ( __mf ) -# define OSD_ATOMIC_SYNC __mf + EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier () + { + __mf (); + } #else # error unexpected target architecture, msvc version of epicsAtomicCD.h #endif -#define OSD_ATOMIC_INLINE_DEFINITION - /* * The windows doc appears to recommend defining InterlockedExchange * to be _InterlockedExchange to cause it to be an intrinsic, but that * creates issues when later, in a windows os specific header, we include - * windows.h so we except some code duplication between the msvc csAtomic.h - * and win32 osdAtomic.h to avoid problems, and to keep the os specific - * windows.h header file out of the msvc cdAtomic.h + * windows.h. Therefore, we except some code duplication between the msvc + * csAtomic.h and win32 osdAtomic.h to avoid problems, and to keep the + * os specific windows.h header file out of the msvc cdAtomic.h */ +#define MS_LONG long +#define MS_InterlockedExchange _InterlockedExchange +#define MS_InterlockedCompareExchange _InterlockedCompareExchange +#define MS_InterlockedIncrement _InterlockedIncrement +#define MS_InterlockedDecrement _InterlockedDecrement +#define MS_InterlockedExchange _InterlockedExchange +#define MS_InterlockedExchangeAdd _InterlockedExchangeAdd +#if defined ( MS_ATOMIC_64 ) +# define MS_LONGLONG long long +# define MS_InterlockedIncrement64 _InterlockedIncrement64 +# define MS_InterlockedDecrement64 _InterlockedDecrement64 +# define MS_InterlockedExchange64 _InterlockedExchange64 +# define MS_InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +# define MS_InterlockedCompareExchange64 _InterlockedCompareExchange64 +#endif + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/* necessary for next three functions */ -STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) ); - -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +#define EPICS_ATOMIC_READ_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () { - *pTarget = newVal; - OSD_ATOMIC_SYNC (); + epicsAtomicMemoryBarrier (); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () { - *pTarget = newVal; - OSD_ATOMIC_SYNC (); + epicsAtomicMemoryBarrier (); } -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT newVal ) -{ - *pTarget = newVal; - OSD_ATOMIC_SYNC (); -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) -{ - OSD_ATOMIC_SYNC (); - return *pTarget; -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - OSD_ATOMIC_SYNC (); - return *pTarget; -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - OSD_ATOMIC_SYNC (); - return *pTarget; -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) -{ - long * const pTarg = ( long * ) ( pTarget ); - return (unsigned) _InterlockedCompareExchange ( pTarg, - (long) newVal, (long) oldVal ); -} - -#if ! OSD_ATOMIC_64 - -/* - * necessary for next five functions - * - * looking at the MS documentation it appears that they will - * keep type long the same size as an int on 64 bit builds - */ -STATIC_ASSERT ( sizeof ( long ) == sizeof ( size_t ) ); - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - long * const pTarg = ( long * ) pTarget; - return _InterlockedIncrement ( pTarg ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - long * const pTarg = ( long * ) ( pTarget ); - return _InterlockedDecrement ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - long * const pTarg = ( long * ) ( pTarget ); - return (EpicsAtomicPtrT) _InterlockedCompareExchange ( pTarg, - (long) newVal, (long) oldVal ); -} - -#else /* ! OSD_ATOMIC_64 */ - -/* - * necessary for next five functions - */ -STATIC_ASSERT ( sizeof ( long long ) == sizeof ( size_t ) ); - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - long long * const pTarg = ( long long * ) pTarget; - return _InterlockedIncrement64 ( pTarg ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - long long * const pTarg = ( long long * ) ( pTarget ); - return _InterlockedDecrement64 ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - long long * const pTarg = ( longlong * ) ( pTarget ); - return (EpicsAtomicPtrT) _InterlockedCompareExchange64 ( pTarg, - (long long) newVal, (long long) oldVal ); -} - -#endif /* ! OSD_ATOMIC_64 */ - #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ +#include "epicsAtomicMS.h" +#include "epicsAtomicDefault.h" + #else /* ifdef _MSC_EXTENSIONS */ #if defined ( __cplusplus ) -# define OSD_ATOMIC_INLINE inline -# include "epicsAtomicOSD.h" +# define EPICS_ATOMIC_INLINE inline #endif +/* + * if unavailable as an intrinsic we will try + * for os specific solution + */ +#include "epicsAtomicOSD.h" + #endif /* ifdef _MSC_EXTENSIONS */ #endif /* epicsAtomicCD_h */ + diff --git a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h index c72a3e203..e247a5e49 100644 --- a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h @@ -17,9 +17,9 @@ #define epicsAtomicCD_h #if defined ( __cplusplus ) -# define OSD_ATOMIC_INLINE inline +# define EPICS_ATOMIC_INLINE inline #else -# define OSD_ATOMIC_INLINE __inline +# define EPICS_ATOMIC_INLINE __inline #endif #include "epicsAtomicOSD.h" diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index aa389ea2f..436da7bd0 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -25,60 +25,69 @@ extern "C" { typedef void * EpicsAtomicPtrT; +/* load target into cache */ +epicsShareFunc void epicsAtomicReadMemoryBarrier (); + +/* push cache version of target into target */ +epicsShareFunc void epicsAtomicWriteMemoryBarrier (); + /* * lock out other smp processors from accessing the target, - * sync target in cache, add one to target, flush target in - * cache, allow other smp processors to access the target, + * load target into cache, add one to target, flush cache + * to target, allow other smp processors to access the target, * return new value of target as modified by this operation - * - * increment is chosen as the primitive here because, - * compared to add, it is more likely to be implemented - * atomically on old architectures such as 68k */ epicsShareFunc size_t epicsAtomicIncrSizeT ( size_t * pTarget ); +epicsShareFunc int epicsAtomicIncrIntT ( int * pTarget ); /* * lock out other smp processors from accessing the target, - * sync target in cache, subtract one from target, flush target - * in cache, allow out other smp processors to access the target, + * load target into cache, subtract one from target, flush cache + * to target, allow out other smp processors to access the target, * return new value of target as modified by this operation - * - * decrement is chosen as the primitive here because, - * compared to subtract, it is more likely to be implemented - * atomically on old architectures such as 68k */ epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget ); +epicsShareFunc int epicsAtomicDecrIntT ( int * pTarget ); /* - * set target in cache, flush target in cache + * lock out other smp processors from accessing the target, + * load target into cache, add/sub delta to/from target, flush cache + * to target, allow other smp processors to access the target, + * return new value of target as modified by this operation + */ +epicsShareFunc size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ); +epicsShareFunc size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ); +epicsShareFunc int epicsAtomicAddIntT ( int * pTarget, int delta ); + +/* + * set cache version of target, flush cache to target */ epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue ); -epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue ); +epicsShareFunc void epicsAtomicSetIntT ( int * pTarget, int newValue ); epicsShareFunc void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue ); /* - * fetch target in cache, return new value of target + * fetch target into cache, return new value of target */ epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget ); -epicsShareFunc unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ); +epicsShareFunc int epicsAtomicGetIntT ( const int * pTarget ); epicsShareFunc EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ); /* * lock out other smp processors from accessing the target, - * sync target in cache, if target is equal to oldVal set target - * to newVal, flush target in cache, allow other smp processors + * load target into cache, if target is equal to oldVal set target + * to newVal, flush cache to target, allow other smp processors * to access the target, return the original value stored in the * target - * - * !!!! beware, this will not guarantee an atomic operation - * !!!! on legacy vxWorks (prior to 6.6) if the target operand - * !!!! is on a multi-commander bus (such as the VME bus) */ -epicsShareFunc unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ); -epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); - +epicsShareFunc size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldVal, size_t newVal ); +epicsShareFunc int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ); +epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, + EpicsAtomicPtrT newVal ); #ifdef __cplusplus } /* end of extern "C" */ @@ -87,7 +96,141 @@ epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTa /* * options for inline compiler instrinsic or os specific * implementations of the above function prototypes + * + * its importnat for certaiin compiler to define the + * inline functions before they get used in the c++ + * code below */ #include "epicsAtomicCD.h" +#ifdef __cplusplus + +namespace epics { +namespace atomic { + +/* + * overloaded c++ interface + */ +epicsShareFunc size_t increment ( size_t & v ); +epicsShareFunc int increment ( int & v ); +epicsShareFunc size_t decrement ( size_t & v ); +epicsShareFunc int decrement ( int & v ); +epicsShareFunc size_t add ( size_t & v, size_t delta ); +epicsShareFunc int add ( int & v, int delta ); +epicsShareFunc size_t subtract ( size_t & v, size_t delta ); +epicsShareFunc int subtract ( int & v, int delta ); +epicsShareFunc void set ( size_t & v , size_t newValue ); +epicsShareFunc void set ( int & v, int newValue ); +epicsShareFunc void set ( EpicsAtomicPtrT & v, + EpicsAtomicPtrT newValue ); +epicsShareFunc size_t get ( const size_t & v ); +epicsShareFunc int get ( const int & v ); +epicsShareFunc EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v ); +epicsShareFunc size_t compareAndSwap ( size_t & v, size_t oldVal, + size_t newVal ); +epicsShareFunc int compareAndSwap ( int & v, int oldVal, int newVal ); +epicsShareFunc EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v, + EpicsAtomicPtrT oldVal, + EpicsAtomicPtrT newVal ); + +/************* incr ***************/ +inline size_t increment ( size_t & v ) +{ + return epicsAtomicIncrSizeT ( & v ); +} + +inline int increment ( int & v ) +{ + return epicsAtomicIncrIntT ( & v ); +} + +/************* decr ***************/ +inline size_t decrement ( size_t & v ) +{ + return epicsAtomicDecrSizeT ( & v ); +} + +inline int decrement ( int & v ) +{ + return epicsAtomicDecrIntT ( & v ); +} + +/************* add ***************/ +inline size_t add ( size_t & v, size_t delta ) +{ + return epicsAtomicAddSizeT ( & v, delta ); +} + +inline int add ( int & v, int delta ) +{ + return epicsAtomicAddIntT ( & v, delta ); +} + +/************* sub ***************/ +inline size_t subtract ( size_t & v, size_t delta ) +{ + return epicsAtomicSubSizeT ( & v, delta ); +} + +inline int subtract ( int & v, int delta ) +{ + return epicsAtomicAddIntT ( & v, -delta ); +} + +/************* set ***************/ +inline void set ( size_t & v , size_t newValue ) +{ + epicsAtomicSetSizeT ( & v, newValue ); +} + +inline void set ( int & v, int newValue ) +{ + epicsAtomicSetIntT ( & v, newValue ); +} + +inline void set ( EpicsAtomicPtrT & v, EpicsAtomicPtrT newValue ) +{ + epicsAtomicSetPtrT ( & v, newValue ); +} + +/************* get ***************/ +inline size_t get ( const size_t & v ) +{ + return epicsAtomicGetSizeT ( & v ); +} + +inline int get ( const int & v ) +{ + return epicsAtomicGetIntT ( & v ); +} + +inline EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v ) +{ + return epicsAtomicGetPtrT ( & v ); +} + +/************* cas ***************/ +inline size_t compareAndSwap ( size_t & v, + size_t oldVal, size_t newVal ) +{ + return epicsAtomicCmpAndSwapSizeT ( & v, oldVal, newVal ); +} + +inline int compareAndSwap ( int & v, int oldVal, int newVal ) +{ + return epicsAtomicCmpAndSwapIntT ( & v, oldVal, newVal ); +} + +inline EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v, + EpicsAtomicPtrT oldVal, + EpicsAtomicPtrT newVal ) +{ + return epicsAtomicCmpAndSwapPtrT ( & v, oldVal, newVal ); +} + +} /* end of namespace atomic */ +} /* end of namespace epics */ + +#endif /* ifdef __cplusplus */ + #endif /* epicsAtomic_h */ diff --git a/src/libCom/osi/epicsAtomicDefault.h b/src/libCom/osi/epicsAtomicDefault.h new file mode 100644 index 000000000..ff1f91114 --- /dev/null +++ b/src/libCom/osi/epicsAtomicDefault.h @@ -0,0 +1,235 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomicDefault_h +#define epicsAtomicDefault_h + +/* + * EPICS_ATOMIC_INLINE might be defined, but empty for an out-of-line + * instantiation + */ +#ifdef EPICS_ATOMIC_INLINE + +#ifdef __cpluplus +extern "C" { +#endif + +/* + * struct EpicsAtomicLockKey; + * epicsShareFunc void epicsAtomicReadMemoryBarrier (); + * epicsShareFunc void epicsAtomicWriteMemoryBarrier (); + * epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * ); + * epicsShareFunc void epicsAtomicUnock ( struct EpicsAtomicLockKey * ); + */ + +/* + * incr + */ +#ifndef EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const int result = ++(*pTarget); + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +#ifndef EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const size_t result = ++(*pTarget); + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +/* + * decr + */ +#ifndef EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const int result = --(*pTarget); + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +#ifndef EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const size_t result = --(*pTarget); + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +/* + * add/sub + */ +#ifndef EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const int result = *pTarget += delta; + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +#ifndef EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const size_t result = *pTarget += delta; + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +#ifndef EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const size_t result = *pTarget -= delta; + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +/* + * set + */ +#ifndef EPICS_ATOMIC_SET_INTT +EPICS_ATOMIC_INLINE void epicsAtomicSetIntT ( int * pTarget, int newVal ) +{ + *pTarget = newVal; + epicsAtomicWriteMemoryBarrier (); +} +#endif + +#ifndef EPICS_ATOMIC_SET_SIZET +EPICS_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + *pTarget = newVal; + epicsAtomicWriteMemoryBarrier (); +} +#endif + +#ifndef EPICS_ATOMIC_SET_PTRT +EPICS_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT newVal ) +{ + *pTarget = newVal; + epicsAtomicWriteMemoryBarrier (); +} +#endif + +/* + * get + */ +#ifndef EPICS_ATOMIC_GET_INTT +EPICS_ATOMIC_INLINE int epicsAtomicGetIntT ( const int * pTarget ) +{ + epicsAtomicReadMemoryBarrier (); + return *pTarget; +} +#endif + +#ifndef EPICS_ATOMIC_GET_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + epicsAtomicReadMemoryBarrier (); + return *pTarget; +} +#endif + +#ifndef EPICS_ATOMIC_GET_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT + epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + epicsAtomicReadMemoryBarrier (); + return *pTarget; +} +#endif + +/* + * cmp and swap + */ +#ifndef EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, int oldval, int newval ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const int cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + epicsAtomicUnlock ( & key ); + return cur; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldval, size_t newval ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const size_t cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + epicsAtomicUnlock ( & key ); + return cur; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const EpicsAtomicPtrT cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + epicsAtomicUnlock ( & key ); + return cur; +} +#endif + +#ifdef __cpluplus +} /* end of extern "C" */ +#endif + +#endif /* EPICS_ATOMIC_INLINE */ + +#endif /* epicsAtomicDefault_h */ + + diff --git a/src/libCom/osi/epicsAtomicGuard.h b/src/libCom/osi/epicsAtomicGuard.h deleted file mode 100644 index b9cf2a74d..000000000 --- a/src/libCom/osi/epicsAtomicGuard.h +++ /dev/null @@ -1,55 +0,0 @@ - -/*************************************************************************\ -* Copyright (c) 2011 LANS LLC, as Operator of -* Los Alamos National Laboratory. -* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author Jeffrey O. Hill - * johill@lanl.gov - */ - -#ifndef epicsAtomicGuard_h -#define epicsAtomicGuard_h - -// -// This header file is intended only for use with the epicsAtomicLocked -// header file. The intent is that an OS specific implementation of -// epicsAtomicOSD.cpp might first include this file, next implement -// AtomicGuard depending on os specific capabilities, and finally include -// the epicsAtomicLocked header file to define the various epicsAtomicXxxx -// functions. -// -// The AtomicGuard class is defined in a seperate header file -// from the epicsAtomicLocked header for two reasons. -// o First, it must be possible to have an inline definition of the -// AtomicGuard member functions, and that isnt possible if the -// epicsAtomicXxxx function definitions in the epicsAtomicLocked -// header file have already been seen by the translation unit. -// o Second, we need to enforce a uniform interface for all definitions -// of the the AtomicGuard constructor and destructor member functions -// requiring that no exception are thrown. This is because the -// epicsAtomicXxxx functions in the epicsAtomicLocked header file are -// directly callable by C code. -// -// The epicsAtomicXxxx functions in the epicsAtomicLocked do not pass -// any parameters to the AtomicGuard constructor, and therefore the lock -// used by AtomicGuard is restricted to be a global lock for the entire -// multithreaded executable. Therefore, AtomicGuard will typically -// reference some translation unit scope limited global variable in -// the anonymous namespace for implementation of the locking primitive. -// - -namespace { - struct AtomicGuard { - AtomicGuard () throw (); - ~AtomicGuard () throw (); - }; -} // end of anonymous namespace - -#endif // ifndef epicsAtomicGuard_h - diff --git a/src/libCom/osi/epicsAtomicOSD.cpp b/src/libCom/osi/epicsAtomicOSD.cpp deleted file mode 100644 index a1b2ff4f5..000000000 --- a/src/libCom/osi/epicsAtomicOSD.cpp +++ /dev/null @@ -1,45 +0,0 @@ - -/*************************************************************************\ -* Copyright (c) 2011 LANS LLC, as Operator of -* Los Alamos National Laboratory. -* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author Jeffrey O. Hill - * johill@lanl.gov - */ - - #include "epicsAtomic.h" - - /* - * OSD_ATOMIC_INLINE - * defined: define atomic functions in osdAtomic.h - * undefined: dont define atomic functions in osdAtomic.h - * - * OSD_ATOMIC_INLINE is typically set by the compiler specific file cdAtomic.h - * - * when we discover here that there is no implementation, and we guess that - * there isnt an inline keyword in the compiler then we define OSD_ATOMIC_INLINE - * empty and include osdAtomic.h to force an out of line implementation - * - * My first inclination was to place only one file of this type under os/default, - * but then this source file always includes default/osdAtomic.h, which isnt correct - * if a more specific os/xxx/osdAtromic.h exists, and so rather than duplicate an - * identical file in all of the os directories (that will get rediculous if there - * is ever a posix interface for the atomics) I moved it here to the osi directory. - * Another option would be to not make tthe current location be the first search - * in the gnu make VPATH, but I am somewhat nervous about changing something that - * fundamental in the build system. - * - * this behavior will work most of the time by defualt but it can always be - * replaced by an os specific implementation, which might be required if - * some of the functions are inline and some are not - */ - #ifndef OSD_ATOMIC_INLINE - # include "osdAtomic.h" - #endif - diff --git a/src/libCom/osi/os/WIN32/epicsAtomicMS.h b/src/libCom/osi/os/WIN32/epicsAtomicMS.h new file mode 100644 index 000000000..bab1da4a4 --- /dev/null +++ b/src/libCom/osi/os/WIN32/epicsAtomicMS.h @@ -0,0 +1,222 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomicMS_h +#define epicsAtomicMS_h + +#include "epicsAssert.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef EPICS_ATOMIC_INCR_INTT +#define EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) pTarget; + return MS_InterlockedIncrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_INTT +#define EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return MS_InterlockedDecrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_ADD_INTT +#define EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + /* we dont use InterlockedAdd because only latest windows is supported */ + return delta + ( int ) MS_InterlockedExchangeAdd ( pTarg, + ( MS_LONG ) delta ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_INTT +#define EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return (int) MS_InterlockedCompareExchange ( pTarg, + (MS_LONG) newVal, (MS_LONG) oldVal ); +} +#endif + +#if ! defined ( MS_ATOMIC_64 ) + +/* + * necessary for next three functions + * + * looking at the MS documentation it appears that they will + * keep type long the same size as an int on 64 bit builds + */ +STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( size_t ) ); + +#ifndef EPICS_ATOMIC_INCR_SIZET +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) pTarget; + return MS_InterlockedIncrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_SIZET +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return MS_InterlockedDecrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_ADD_SIZET +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, + size_t delta ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + /* we dont use InterlockedAdd because only latest windows is supported */ + return delta + ( size_t ) MS_InterlockedExchangeAdd ( pTarg, + ( MS_LONG ) delta ); +} +#endif + +#ifndef EPICS_ATOMIC_SUB_SIZET +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + MS_LONG ldelta = (MS_LONG) delta; + /* we dont use InterlockedAdd because only latest windows is supported */ + return ( ( size_t ) MS_InterlockedExchangeAdd ( pTarg, -ldelta ) ) - delta; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_SIZET +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( + size_t * pTarget, + size_t oldVal, size_t newVal ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return (size_t) MS_InterlockedCompareExchange ( pTarg, + (MS_LONG) newVal, (MS_LONG) oldVal ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_PTRT +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return (EpicsAtomicPtrT) MS_InterlockedCompareExchange ( pTarg, + (MS_LONG) newVal, (MS_LONG) oldVal ); +} +#endif + +#else /* ! MS_ATOMIC_64 */ + +/* + * necessary for next three functions + */ +STATIC_ASSERT ( sizeof ( MS_LONGLONG ) == sizeof ( size_t ) ); + +#ifndef EPICS_ATOMIC_INCR_SIZET +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) pTarget; + return ( size_t ) MS_InterlockedIncrement64 ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_SIZET +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + return ( size_t ) MS_InterlockedDecrement64 ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_ADD_SIZET +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + /* we dont use InterlockedAdd64 because only latest windows is supported */ + return delta + ( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, + ( MS_LONGLONG ) delta ); +} +#endif + +#ifndef EPICS_ATOMIC_SUB_SIZET +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + MS_LONGLONG ldelta = (MS_LONGLONG) delta; + /* we dont use InterlockedAdd64 because only latest windows is supported */ + return (( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, -ldelta )) - delta; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_SIZET +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldVal, size_t newVal ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + return (size_t) MS_InterlockedCompareExchange64 ( pTarg, + (MS_LONGLONG) newVal, + (MS_LONGLONG) oldVal ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_PTRT +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + return (EpicsAtomicPtrT) MS_InterlockedCompareExchange64 ( pTarg, + (MS_LONGLONG) newVal, (MS_LONGLONG) oldVal ); +} +#endif + +#endif /* ! MS_ATOMIC_64 */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#endif /* ifdef epicsAtomicMS_h */ + diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.cpp b/src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp similarity index 56% rename from src/libCom/osi/os/default/epicsAtomicOSD.cpp rename to src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp index ecb1ad7c9..b7f7b17c2 100644 --- a/src/libCom/osi/os/default/epicsAtomicOSD.cpp +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp @@ -14,13 +14,9 @@ #define epicsExportSharedSymbols #include "epicsAtomic.h" -// -// We need a default epicsAtopmicOSD.cpp which is empty for use when -// a compiler or inline OS specific implementation is provided. See -// "osi/os/posix/epicsAtomicOSD.cpp" for an example OS specific generic -// out-of-line implementation based on a mutex lock. -// -#if ! defined ( OSD_ATOMIC_INLINE_DEFINITION ) -# error the epicsAtomicXxxxx functions definitions are misssing +// if the compiler is unable to inline then instantiate out-of-line +#ifndef EPICS_ATOMIC_INLINE +#define EPICS_ATOMIC_INLINE +#include "epicsAtomic.h" #endif diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index bcf48facd..f9378c1c6 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -12,149 +12,38 @@ * Author Jeffrey O. Hill * johill@lanl.gov */ - + #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#if defined ( OSD_ATOMIC_INLINE ) - -#include - -#include "epicsAssert.h" - -#define STRICT #define VC_EXTRALEAN -#include +#define STRICT +#include "windows.h" -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +#if defined ( _WIN64 ) +# define MS_ATOMIC_64 +#endif -#define OSD_ATOMIC_INLINE_DEFINITION +#define MS_LONG LONG +#define MS_InterlockedExchange InterlockedExchange +#define MS_InterlockedCompareExchange InterlockedCompareExchange +#define MS_InterlockedIncrement InterlockedIncrement +#define MS_InterlockedDecrement InterlockedDecrement +#define MS_InterlockedExchange InterlockedExchange +#define MS_InterlockedExchangeAdd InterlockedExchangeAdd +#if defined ( MS_ATOMIC_64 ) +# define MS_LONGLONG LONGLONG +# define MS_InterlockedIncrement64 InterlockedIncrement64 +# define MS_InterlockedDecrement64 InterlockedDecrement64 +# define MS_InterlockedExchange64 InterlockedExchange64 +# define MS_InterlockedExchangeAdd64 InterlockedExchangeAdd64 +# define MS_InterlockedCompareExchange InterlockedCompareExchange64 +#endif -/* - * mingw doesnt currently provide MemoryBarrier - * (this is mostly for testing purposes as the gnu - * intrinsics are used if compiling for 486 or better - * minimum hardware) - */ -#ifdef __MINGW32__ - extern inline void MemoryBarrier() { - int fence = 0; - __asm__ __volatile__( "xchgl %%eax,%0 ":"=r" (fence) ); - } -#endif // ifdef __MINGW32__ +#ifdef EPICS_ATOMIC_INLINE +# include "epicsAtomicMS.h" +# include "epicsAtomicDefault.h" +#endif -/* necessary for next three functions */ -STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) ); +#endif /* epicsAtomicOSD_h */ -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) -{ - *pTarget = newVal; - MemoryBarrier (); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - *pTarget = newVal; - MemoryBarrier (); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - *pTarget = newVal; - MemoryBarrier (); -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) -{ - MemoryBarrier (); - return *pTarget; -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - MemoryBarrier (); - return *pTarget; -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - MemoryBarrier (); - return *pTarget; -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) -{ - LONG * const pTarg = ( LONG * ) ( pTarget ); - return (unsigned) InterlockedCompareExchange ( pTarg, - (LONG) newVal, (LONG) oldVal ); -} - -#if defined ( _WIN32 ) - -/* - * necessary for next five functions - * - * looking at the MS documentation it appears that they will - * keep type long the same size as an int on 64 bit builds - */ -STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( size_t ) ); - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - LONG * const pTarg = ( LONG * ) pTarget; - return InterlockedIncrement ( pTarg ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - LONG * const pTarg = ( LONG * ) ( pTarget ); - return InterlockedDecrement ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - LONG * const pTarg = ( LONG * ) ( pTarget ); - return (EpicsAtomicPtrT) InterlockedCompareExchange ( pTarg, - (LONG) newVal, (LONG) oldVal ); -} - -#elif defined ( _WIN64 ) - -/* - * necessary for next five functions - */ -STATIC_ASSERT ( sizeof ( LONGLONG ) == sizeof ( size_t ) ); - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - LONGLONG * const pTarg = ( LONGLONG * ) pTarget; - return InterlockedIncrement64 ( pTarg ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); - return InterlockedDecrement64 ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); - return (EpicsAtomicPtrT) InterlockedCompareExchange64 ( pTarg, - (LONGLONG) newVal, (LONGLONG) oldVal ); -} - -#endif /* if defined ( _WIN32 ) */ - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif /* __cplusplus */ - -#endif /* if defined ( OSD_ATOMIC_INLINE ) */ - -#endif /* ifndef epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp index 5e182d748..2fb06c36f 100644 --- a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp @@ -9,67 +9,100 @@ /* * Author Jeffrey O. Hill * johill@lanl.gov - * - * Provide a global mutex version of AtomicGuard on POSIX - * systems for when we dont have more efficent compiler or - * OS primitives intriniscs to use instead. - * - * We implement this mutex-based AtomicGuard primitive directly - * upon the standalone POSIX pthread library so that the epicsAtomic - * library can be used to implement other primitives such - * epicsThreadOnce. - * - * We use a static initialized pthread mutex to minimize code - * size, and are also optimistic that this can be more efficent - * than pthread_once. */ +#define epicsExportSharedSymbols +#include "epicsAtomic.h" + +// if the compiler is unable to inline then instantiate out-of-line +#ifndef EPICS_ATOMIC_INLINE +#define EPICS_ATOMIC_INLINE +#include "epicsAtomic.h" +#endif + +/* Authors: Jeffrey O. Hill */ #include #include #include #define epicsExportSharedSymbols #include "epicsAssert.h" + +// if the compiler is unable to inline then instantiate out-of-line +#ifndef EPICS_ATOMIC_INLINE +#define EPICS_ATOMIC_INLINE #include "epicsAtomic.h" +#endif -// If we have an inline implementation then implement -// nothing that conflicts here -#if ! defined ( OSD_ATOMIC_INLINE_DEFINITION ) +#ifndef EPICS_ATOMIC_LOCK -// get the interface for class AtomicGuard -#include "epicsAtomicGuard.h" +/* + * Slow, but probably correct on all systems. + * Useful only if something more efficent isnt + * provided based on knowledge of the compiler + * or OS + * + * A statically initialized pthread mutex doesnt + * need to be destroyed + * + * !!!!! + * !!!!! WARNING + * !!!!! + * !!!!! Do not use this implementation on systems where + * !!!!! code runs at interrupt context. If so, then + * !!!!! an implementation must be provided that is based + * !!!!! on a compiler intrinsic or an interrpt lock and or + * !!!!! a spin lock primitive + * !!!!! + */ +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -namespace { - -// a statically initialized mutex doesnt need to be destroyed -pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -inline AtomicGuard :: AtomicGuard () throw () +void epicsAtomicLock ( EpicsAtomicLockKey * ) { unsigned countDown = 1000u; int status; while ( true ) { status = pthread_mutex_lock ( & mutex ); - if ( status != EINTR ) break; + if ( status == 0 ) return; + assert ( status == EINTR ); static const useconds_t retryDelayUSec = 100000; usleep ( retryDelayUSec ); countDown--; assert ( countDown ); } - assert ( status == 0 ); } -inline AtomicGuard :: ~AtomicGuard () throw () +void epicsAtomicUnlock ( EpicsAtomicLockKey * ) { const int status = pthread_mutex_unlock ( & mutex ); assert ( status == 0 ); } -} // end of namespace anonymous +#endif // ifndef EPICS_ATOMIC_LOCK -// Define the epicsAtomicXxxx functions out-of-line using this -// implementation of AtomicGuard. Note that this isnt a traditional -// c++ header file. -#include "epicsAtomicLocked.h" +#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER +// Slow, but probably correct on all systems. +// Useful only if something more efficent isnt +// provided based on knowledge of the compiler +// or OS +void epicsAtomicReadMemoryBarrier () +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + epicsAtomicUnlock ( & key ); +} +#endif + +#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER +// Slow, but probably correct on all systems. +// Useful only if something more efficent isnt +// provided based on knowledge of the compiler +// or OS +void epicsAtomicWriteMemoryBarrier () +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + epicsAtomicUnlock ( & key ); +} +#endif -#endif // if ! defined ( #define OSD_ATOMIC_INLINE_DEFINITION ) diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.h b/src/libCom/osi/os/posix/epicsAtomicOSD.h similarity index 61% rename from src/libCom/osi/os/default/epicsAtomicOSD.h rename to src/libCom/osi/os/posix/epicsAtomicOSD.h index bf09ae083..5446f23ef 100644 --- a/src/libCom/osi/os/default/epicsAtomicOSD.h +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.h @@ -16,4 +16,17 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h +struct EpicsAtomicLockKey {}; +epicsShareFunc void epicsAtomicReadMemoryBarrier (); +epicsShareFunc void epicsAtomicWriteMemoryBarrier (); +epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * ); +epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * ); + +#ifdef EPICS_ATOMIC_INLINE + +#include "epicsAtomicDefault.h" + +#endif /* ifdef EPICS_ATOMIC_INLINE */ + #endif /* epicsAtomicOSD_h */ + diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 48c95824a..e377a770b 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -16,84 +16,141 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#if defined ( OSD_ATOMIC_INLINE ) +#if defined ( EPICS_ATOMIC_INLINE ) /* * atomic.h exists only in Solaris 10 or higher */ #if defined ( __SunOS_5_10 ) -#include #include -#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ -#include - -#define OSD_ATOMIC_INLINE_DEFINITION - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) +#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER +#define EPICS_ATOMIC_READ_MEMORY_BARRIER +EPICS_ATOMIC_INLINE int epicsAtomicReadMemoryBarrier () { - return atomic_cas_uint ( pTarget, oldVal, newVal ); + membar_consumer (); } +#endif -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER +#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER +EPICS_ATOMIC_INLINE int epicsAtomicWriteMemoryBarrier () +{ + membar_producer (); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_INTT +#define EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ) +{ + STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); + return ( int ) atomic_cas_uint ( pTarget, ( unsigned ) oldVal, + ( unsigned ) newVal ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_SIZET +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapSizeT ( + size_t * pTarget, + size_t oldVal, size_t newVal ) +{ + STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); + void ** ppPtr = (void **) pTarget; + return ( size_t ) atomic_cas_ptr ( ppPtr, ( void * )oldVal, ( void * )newVal ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_PTRT +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, + EpicsAtomicPtrT newVal ) { return atomic_cas_ptr ( pTarget, oldVal, newVal ); } +#endif -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +#ifndef EPICS_ATOMIC_INCR_INTT +#define EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) { - void * const pTarg = ( void * ) ( pTarget ); - return ( size_t ) atomic_inc_ptr_nv ( pTarg ); + STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return ( int ) atomic_inc_uint_nv ( pTarg ); } +#endif -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +#ifndef EPICS_ATOMIC_INCR_SIZET +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - void * const pTarg = ( void * ) ( pTarget ); - return atomic_dec_ptr_nv ( pTarg ); + STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); + void ** const ppTarg = ( void ** ) ( pTarget ); + return ( size_t ) atomic_inc_ptr_nv ( ppTarg ); } +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +#ifndef EPICS_ATOMIC_DECR_INTT +#define EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) { - *pTarget = newVal; - membar_producer(); + STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return ( int ) atomic_dec_uint_nv ( pTarg ); } +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +#ifndef EPICS_ATOMIC_DECR_SIZET +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - *pTarget = newVal; - membar_producer(); + STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); + void ** const pTarg = ( void ** ) ( pTarget ); + return ( size_t ) atomic_dec_ptr_nv ( pTarg ); } +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +#ifndef EPICS_ATOMIC_ADD_INTT +#define EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) { - *pTarget = newVal; - membar_producer(); + STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return ( int ) atomic_add_int_nv ( pTarg, delta ); } +#endif -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +#ifndef EPICS_ATOMIC_ADD_SIZET +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, + size_t delta ) { - membar_consumer (); - return *pTarget; + STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); + void ** const pTarg = ( void ** ) ( pTarget ); + return ( size_t ) atomic_add_ptr_nv ( pTarg, ( ssize_t ) delta ); } +#endif -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +#ifndef EPICS_ATOMIC_SUB_SIZET +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, + size_t delta ) { - membar_consumer (); - return *pTarget; -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - membar_consumer (); - return *pTarget; + STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); + void ** const pTarg = ( void ** ) ( pTarget ); + ssize_t = sdelta = ( ssize_t ) delta; + return ( size_t ) atomic_add_ptr_nv ( pTarg, -sdelta ); } +#endif #ifdef __cplusplus } /* end of extern "C" */ @@ -101,6 +158,9 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * p #endif /* ifdef __SunOS_5_10 */ -#endif /* if defined ( OSD_ATOMIC_INLINE ) */ +#include "epicsAtomicDefault.h" + +#endif /* if defined ( EPICS_ATOMIC_INLINE ) */ #endif /* epicsAtomicOSD_h */ + diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp new file mode 100644 index 000000000..b7f7b17c2 --- /dev/null +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp @@ -0,0 +1,22 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#define epicsExportSharedSymbols +#include "epicsAtomic.h" + +// if the compiler is unable to inline then instantiate out-of-line +#ifndef EPICS_ATOMIC_INLINE +#define EPICS_ATOMIC_INLINE +#include "epicsAtomic.h" +#endif + diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index b7a9e0f4b..c54a2b4c2 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -15,13 +15,11 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#if defined ( OSD_ATOMIC_INLINE ) +#if defined ( EPICS_ATOMIC_INLINE ) #include "vxWorks.h" /* obtain the version of vxWorks */ #include "epicsAssert.h" -#define OSD_ATOMIC_INLINE_DEFINITION - /* * With vxWorks 6.6 and later we need to use vxAtomicLib * to implement this functionality correctly on SMP systems @@ -35,6 +33,22 @@ extern "C" { #endif /* __cplusplus */ +#ifndef EPICS_READ_MEMORY_BARRIER +#define EPICS_READ_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsReadMemoryBarrier () +{ + VX_MEM_BARRIER_R (); +} +#endif + +#ifndef EPICS_WRITE_MEMORY_BARRIER +#define EPICS_WRITE_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsWriteMemoryBarrier () +{ + VX_MEM_BARRIER_W (); +} +#endif + /* * we make the probably correct guess that if ULONG_MAX * is the same as UINT_MAX then sizeof ( atomic_t ) @@ -48,127 +62,134 @@ extern "C" { #if ULONG_MAX == UINT_MAX STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) ); +STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( EpicsAtomicPtrT ) ); -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) + +#ifndef EPICS_ATOMIC_INCR_SIZET +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + const atomic_t oldVal = vxAtomicInc ( pTarg ); + return 1 + ( size_t ) ( oldVal ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_SIZET +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + const atomic_t oldVal = vxAtomicDec ( pTarg ); + return ( ( size_t ) oldVal ) - 1u; +} +#endif + +#ifndef EPICS_ATOMIC_ADD_SIZET +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) { /* - * vxAtomicLib doc indicates that vxAtomicInc is - * implemented using unsigned arithmetic + * vxAtomicLib doc indicates that vxAtomicAdd is + * implemented using signed arithmetic, but it + * does not change the end result because twos + * complement addition is used in either case */ atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - const atomic_t oldVal = vxAtomicInc ( pTarg ) + 1; - return ( ( size_t ) ( oldVal ) ) + 1u; -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) + const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta ); + return delta + ( size_t ) oldVal; +} #endif #ifndef EPICS_ATOMIC_SUB_SIZET +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) { /* - * vxAtomicLib doc indicates that vxAtomicDec is - * implemented using unsigned arithmetic + * vxAtomicLib doc indicates that vxAtomicSub is + * implemented using signed arithmetic, but it + * does not change the end result because twos + * complement subtraction is used in either case */ atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - const atomic_t oldVal = vxAtomicDec ( pTarg ) - 1; - return ( ( size_t ) ( oldVal ) ) - 1u; + const atomic_t oldVal = vxAtomicSub ( pTarg, (atomic_t) delta ); + return ( ( size_t ) oldVal ) - delta; } +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +#ifndef EPICS_ATOMIC_CAS_SIZET +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldVal, size_t newVal ) { atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - vxAtomicSet ( pTarg, newVal ); + return ( size_t ) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); } +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - vxAtomicSet ( pTarg, newVal ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return ( size_t ) vxAtomicGet ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return ( EpicsAtomicPtrT ) vxAtomicGet ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, +#ifndef EPICS_ATOMIC_CAS_PTRT +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); return (EpicsAtomicPtrT) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); } +#endif #else /* ULONG_MAX == UINT_MAX */ /* - * if its 64 bit vxWorks and the compiler doesnt + * if its 64 bit SMP vxWorks and the compiler doesnt * have an intrinsic then maybe there isnt any way to * implement these without using a global lock because - * size_t is bigger than atomic_t + * size_t is maybe bigger than atomic_t + * + * I dont yet have access to vxWorks manuals for + * 64 bit systems so this is still undecided, but is + * defaulting now to a global lock */ -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - return epicsLockedIncrSizeT ( pTarget ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - return epicsLockedDecrSizeT ( pTarget ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - epicsLockedSetSizeT ( pTarget, newVal ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - epicsLockedSetPtrT ( pTarget, newVal ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - return epicsLockedGetSizeT ( pTarget ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - return epicsLockedGetPtrT ( pTarget ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); -} #endif /* ULONG_MAX == UINT_MAX */ -STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); +STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( int ) ); -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +#ifndef EPICS_ATOMIC_INCR_INTT +#define EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) { atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - vxAtomicSet ( pTarg, newVal ); + const atomic_t oldVal = vxAtomicInc ( pTarg ); + return 1 + ( int ) oldVal; } +#endif -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) -{ - STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); - atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return ( unsigned ) vxAtomicGet ( pTarg ); -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) +#ifndef EPICS_ATOMIC_DECR_INTT +#define EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) { atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return (unsigned) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); + const atomic_t oldVal = vxAtomicDec ( pTarg ); + return ( ( int ) oldVal ) - 1; } +#endif + +#ifndef EPICS_ATOMIC_ADD_INTT +#define EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta ); + return delta + ( int ) oldVal; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_INTT +#define EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return ( int ) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); +} +#endif #ifdef __cplusplus } /* end of extern "C" */ @@ -183,129 +204,39 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, extern "C" { #endif /* __cplusplus */ -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +#ifndef EPICS_ATOMIC_LOCK +#define EPICS_ATOMIC_LOCK + +typedef struct EpicsAtomicLockKey { int m_key; } EpicsAtomicLockKey; + +EPICS_ATOMIC_INLINE void epicsAtomicLock ( EpicsAtomicLockKey * pKey ) { -# ifdef __m68k__ - return ++(*pTarget); -# else - /* - * no need for memory barrior since this - * is a single cpu system. - */ - const int key = intLock (); - const size_t result = ++(*pTarget); - intUnlock ( key ); - return result; -# endif + pKey->m_key = intLock (); } -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +EPICS_ATOMIC_INLINE EpicsAtomicLockKey epicsAtomicUnlock ( EpicsAtomicLockKey * pKey ) { -# ifdef __m68k__ - return --(*pTarget); -# else - /* - * no need for memory barrior since this - * is a single cpu system - */ - const int key = intLock (); - const size_t result = --(*pTarget); - intUnlock ( key ); - return result; + intUnlock ( pKey->m_key ); +} #endif -} -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - *pTarget = newVal; -} +#ifndef EPICS_READ_MEMORY_BARRIER +#define EPICS_READ_MEMORY_BARRIER +/* + * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system + * (we are not protecting against multiple access to memory mapped IO) + */ +EPICS_ATOMIC_INLINE void epicsReadMemoryBarrier () {} +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - *pTarget = newVal; -} - -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - *pTarget = newVal; -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - return *pTarget; -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - return *pTarget; -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - return *pTarget; -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - * - * !!!! beware, this will not guarantee an atomic operation - * !!!! if the target operand is on the VME bus - */ - const int key = intLock (); - const unsigned curr = *pTarget; - if ( curr == oldVal ) { - *pTarget = newVal; - } - intUnlock ( key ); - return curr; -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - * - * !!!! beware, this will not guarantee an atomic operation - * !!!! if the target operand is on the VME bus - */ - const int key = intLock (); - const EpicsAtomicPtrT curr = *pTarget; - if ( curr == oldVal ) { - *pTarget = newVal; - } - intUnlock ( key ); - return curr; -} +#ifndef EPICS_WRITE_MEMORY_BARRIER +#define EPICS_WRITE_MEMORY_BARRIER +/* + * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system + * (we are not protecting against multiple access to memory mapped IO) + */ +EPICS_ATOMIC_INLINE void epicsWriteMemoryBarrier () {} +#endif #ifdef __cplusplus } /* end of extern "C" */ @@ -313,6 +244,9 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * #endif /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */ -#endif /* if defined ( OSD_ATOMIC_INLINE ) */ +#include "epicsAtomicDefault.h" + +#endif /* if defined ( EPICS_ATOMIC_INLINE ) */ #endif /* epicsAtomicOSD_h */ + diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index 3c94f9850..02649e1ca 100644 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -109,8 +109,8 @@ testHarness_SRCS += epicsMutexTest.cpp TESTS += epicsMutexTest TESTPROD_HOST += epicsAtomicTest -epicsAtomicTest_SRCS += epicsAtomicTest.c -testHarness_SRCS += epicsAtomicTest.c +epicsAtomicTest_SRCS += epicsAtomicTest.cpp +testHarness_SRCS += epicsAtomicTest.cpp TESTS += epicsAtomicTest TESTPROD_HOST += epicsExceptionTest diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp index 3a116008d..98b6e9939 100644 --- a/src/libCom/test/epicsAtomicPerform.cpp +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -1,6 +1,8 @@ #include +#include #include +#include #include "epicsInterrupt.h" #include "epicsAtomic.h" @@ -9,6 +11,8 @@ #include "testMain.h" using std :: size_t; +using namespace epics; +using namespace atomic; class RefCtr { public: @@ -214,234 +218,184 @@ inline void passRefOwnership1000 ( const Ownership & ownershipIn, Ownership & ow time_t extTime = 0; +template < class T > +class OrdinaryIncr { +public: + OrdinaryIncr () : m_target ( 0 ) {} + void run (); + void diagnostic ( double delay ); +private: + T m_target; +}; + // tests the time it takes to perform a call to an external // function and also increment an integer word. The // epicsInterruptIsInterruptContext function is an // out-of-line function implemented in a sharable library // so hopefully it wont be optimized away. -inline void tenOrdinaryIncr ( size_t & target ) +template < class T > +inline void OrdinaryIncr < T > :: run () { - int result = 0; - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - target = static_cast < unsigned > ( result ); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); } -inline void oneHundredOrdinaryIncr ( size_t & target ) +template < class T > +void OrdinaryIncr < T > :: diagnostic ( double delay ) { - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); + delay /= 10.0; + delay *= 1e6; + const char * const pName = typeid ( T ) . name (); + testDiag ( "raw incr of \"%s\" and a NOOP function call takes %f microseconds", + pName, delay ); } -inline void oneThousandOrdinaryIncr ( size_t & target ) +template < class T > +class AtomicIncr { +public: + AtomicIncr () : m_target ( 0 ) {} + void run (); + void diagnostic ( double delay ); +private: + T m_target; +}; + +template < class T > +inline void AtomicIncr < T > :: run () { - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); } -inline void tenAtomicIncr ( size_t & target ) +template < class T > +void AtomicIncr < T > :: diagnostic ( double delay ) { - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); + delay /= 10.0; + delay *= 1e6; + const char * const pName = typeid ( T ) . name (); + testDiag ( "epicsAtomicIncr \"%s\" takes %f microseconds", + pName, delay ); } -inline void oneHundredAtomicIncr ( size_t & target ) +template < class T > T trueValue (); +template < class T > T falseValue (); + +// int +template <> +inline int trueValue < int > () { return 1; } + +template <> +inline int falseValue < int > () { return 0; } + +// size_t +template <> +inline size_t trueValue < size_t > () { return 1u; } + +template <> +inline size_t falseValue < size_t > () { return 0u; } + +// EpicsAtomicPtrT +template <> +inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > () +{ static char c; return & c; } + +template <> +inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > () +{ return 0u; } + +template < class T > +class AtomicCmpAndSwap { +public: + AtomicCmpAndSwap () : m_target ( 0 ) {} + void run (); + void diagnostic ( double delay ); +private: + T m_target; +}; + +template < class T > +inline void AtomicCmpAndSwap < T > :: run () { - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); } -inline void oneThousandAtomicIncr ( size_t & target ) +template < class T > +void AtomicCmpAndSwap < T > :: diagnostic ( double delay ) { - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); + delay /= 10.0; + delay *= 1e6; + const char * const pName = typeid ( T ) . name (); + testDiag ( "epicsAtomicCmpAndSwap of \"%s\" takes %f microseconds", + pName, delay ); } -inline void tenAtomicCmpAndSwap ( unsigned & target ) +template < class T > +class AtomicSet { +public: + AtomicSet () : m_target ( 0 ) {} + void run (); + void diagnostic ( double delay ); +private: + T m_target; +}; + +template < class T > +inline void AtomicSet < T > :: run () { - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); } -inline void oneHundredAtomicCmpAndSwap ( unsigned & target ) +template < class T > +void AtomicSet < T > :: diagnostic ( double delay ) { - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); -} - -inline void oneThousandAtomicCmpAndSwap ( unsigned & target ) -{ - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); -} - -inline void tenAtomicSet ( size_t & target ) -{ - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); -} - -inline void oneHundredAtomicSet ( size_t & target ) -{ - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); -} - -inline void oneThousandAtomicSet ( size_t & target ) -{ - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); + delay /= 10.0; + delay *= 1e6; + const char * const pName = typeid ( T ) . name (); + testDiag ( "epicsAtomicSet of \"%s\" takes %f microseconds", + pName, delay ); } static const unsigned N = 10000; -void ordinaryIncrPerformance () -{ - epicsTime begin = epicsTime::getCurrent (); - size_t target; - epicsAtomicSetSizeT ( & target, 0 ); - for ( unsigned i = 0; i < N; i++ ) { - oneThousandOrdinaryIncr ( target ); - } - double delay = epicsTime::getCurrent () - begin; - testOk1 ( target == 0u ); - delay /= N * 1000u; // convert to delay per call - delay *= 1e6; // convert to micro seconds - testDiag ( "raw incr and a NOOP function call takes %f microseconds", delay ); -} - -void epicsAtomicIncrPerformance () -{ - epicsTime begin = epicsTime::getCurrent (); - size_t target; - epicsAtomicSetSizeT ( & target, 0 ); - for ( unsigned i = 0; i < N; i++ ) { - oneThousandAtomicIncr ( target ); - } - double delay = epicsTime::getCurrent () - begin; - testOk1 ( target == N * 1000u ); - delay /= N * 1000u; // convert to delay per call - delay *= 1e6; // convert to micro seconds - testDiag ( "epicsAtomicIncr() takes %f microseconds", delay ); -} - -void atomicCmpAndSwapPerformance () -{ - epicsTime begin = epicsTime::getCurrent (); - unsigned target; - epicsAtomicSetUIntT ( & target, 0 ); - testOk1 ( ! target ); - for ( unsigned i = 0; i < N; i++ ) { - oneThousandAtomicCmpAndSwap ( target ); - } - double delay = epicsTime::getCurrent () - begin; - testOk1 ( target ); - delay /= N * 1000u; // convert to delay per call - delay *= 1e6; // convert to micro seconds - testDiag ( "epicsAtomicCmpAndSwap() takes %f microseconds", delay ); -} - void recursiveOwnershipRetPerformance () { RefCtr refCtr; epicsTime begin = epicsTime::getCurrent (); - for ( unsigned i = 0; i < N; i++ ) { + for ( size_t i = 0; i < N; i++ ) { Ownership ownership ( refCtr ); recurRetOwner1000 ( ownership ); } @@ -455,7 +409,7 @@ void ownershipPassRefPerformance () { RefCtr refCtr; epicsTime begin = epicsTime::getCurrent (); - for ( unsigned i = 0; i < N; i++ ) { + for ( size_t i = 0; i < N; i++ ) { Ownership ownershipSrc ( refCtr ); Ownership ownershipDest; passRefOwnership1000 ( ownershipSrc, ownershipDest ); @@ -466,34 +420,87 @@ void ownershipPassRefPerformance () testDiag ( "passRefOwnership() takes %f microseconds", delay ); } -void epicsAtomicSetPerformance () +template < class T > +class Ten { - epicsTime begin = epicsTime::getCurrent (); - size_t target; - for ( unsigned i = 0; i < N; i++ ) { - oneThousandAtomicSet ( target ); - } - double delay = epicsTime::getCurrent () - begin; - testOk1 ( target == 0u ); - delay /= N * 1000u; // convert to delay per call - delay *= 1e6; // convert to micro seconds - testDiag ( "epicsAtomicSet() takes %f microseconds", delay ); +public: + void run (); + void diagnostic ( double delay ); + typedef Ten < Ten < T > > Hundred; + typedef Ten < Hundred > Thousand; +private: + T m_target; +}; + +template < class T > +inline void Ten < T > :: run () +{ + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); } -MAIN(epicsAtomicPerform) +template < class T > +void Ten < T > :: diagnostic ( double delay ) { - testPlan(5); + m_target.diagnostic ( delay / 10.0 ); +} + +template < class T > +void measurePerformance () +{ + epicsTime begin = epicsTime::getCurrent (); + T target; + for ( size_t i = 0; i < N; i++ ) { + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + } + double delay = epicsTime::getCurrent () - begin; + delay /= ( N * 10u ); // convert to delay per call + target.diagnostic ( delay ); +} + +template < class T > +void measure () +{ + measurePerformance < typename Ten < T > :: Hundred > (); +} + +MAIN ( epicsAtomicPerform ) +{ + testPlan ( 0 ); // // The tests running here are measuring fast // functions so they tend to be impacted // by where the cache lines are wrt to the - // virtual pages perhaps + // virtual pages perhap // - epicsAtomicSetPerformance (); - ordinaryIncrPerformance (); - epicsAtomicIncrPerformance (); + measure < AtomicSet < int > > (); + measure < AtomicSet < size_t > > (); + measure < AtomicSet < void * > > (); + measure < OrdinaryIncr < int > > (); + measure < OrdinaryIncr < size_t > > (); + measure < AtomicIncr < int > > (); + measure < AtomicIncr < size_t > > (); + measure < AtomicCmpAndSwap < int > > (); + measure < AtomicCmpAndSwap < size_t > > (); + measure < AtomicCmpAndSwap < void * > > (); recursiveOwnershipRetPerformance (); ownershipPassRefPerformance (); - atomicCmpAndSwapPerformance (); return testDone(); } diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c deleted file mode 100644 index 79f90f6d5..000000000 --- a/src/libCom/test/epicsAtomicTest.c +++ /dev/null @@ -1,175 +0,0 @@ - -#include -#include - -#include "epicsAtomic.h" -#include "epicsTime.h" -#include "epicsThread.h" -#include "epicsUnitTest.h" -#include "testMain.h" - -typedef struct TestDataIncrDecr { - size_t m_testValue; - size_t m_testIterations; -} TestDataIncrDecr; - -static void incr ( void *arg ) -{ - TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg; - epicsAtomicIncrSizeT ( & pTestData->m_testValue ); - epicsAtomicIncrSizeT ( & pTestData->m_testIterations ); -} - -static void decr ( void *arg ) -{ - TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg; - epicsAtomicDecrSizeT ( & pTestData->m_testValue ); - epicsAtomicIncrSizeT ( & pTestData->m_testIterations ); -} - -typedef struct TestDataTNS_UIntT { - unsigned m_testValue; - size_t m_testIterationsSet; - size_t m_testIterationsNotSet; -} TestDataTNS_UIntT; - -typedef struct TestDataTNS_PtrT { - EpicsAtomicPtrT m_testValue; - size_t m_testIterationsSet; - size_t m_testIterationsNotSet; -} TestDataTNS_PtrT; - - -int isModulo ( size_t N, size_t n ) -{ - return ( n % N ) == 0u; -} - -static void tns_UIntT ( void *arg ) -{ - TestDataTNS_UIntT * const pTestData = (TestDataTNS_UIntT *) arg; - /* - * intentionally waste cpu and maximize - * contention for the shared data - */ - epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); - while ( ! epicsAtomicCmpAndSwapUIntT ( & pTestData->m_testValue, 0u, 1u ) ) { - } - epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); - epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u ); - epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); -} - -static void tns_PtrT ( void *arg ) -{ - static char dummy = 0; - TestDataTNS_PtrT * const pTestData = (TestDataTNS_PtrT *) arg; - /* - * intentionally waste cpu and maximize - * contention for the shared data - */ - epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); - while ( ! epicsAtomicCmpAndSwapPtrT ( & pTestData->m_testValue, 0, & dummy ) ) { - } - epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); - epicsAtomicSetPtrT ( & pTestData->m_testValue, 0u ); - epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); -} - -MAIN(osiAtomicTest) -{ - const unsigned int stackSize = - epicsThreadGetStackSize ( epicsThreadStackSmall ); - - testPlan(14); - - { - static const size_t N = 100; - size_t i; - TestDataIncrDecr testData = { 0, N };; - epicsAtomicSetSizeT ( & testData.m_testValue, N ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, - "set/get %u", testData.m_testValue ); - epicsAtomicSetSizeT ( & testData.m_testIterations, 0u ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 0u, - "set/get %u", testData.m_testIterations ); - for ( i = 0u; i < N; i++ ) { - epicsThreadCreate ( "incr", - 50, stackSize, incr, & testData ); - epicsThreadCreate ( "decr", - 50, stackSize, decr, & testData ); - } - while ( testData.m_testIterations < 2 * N ) { - epicsThreadSleep ( 0.01 ); - } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N, - "incr/decr iterations %u", - testData.m_testIterations ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, - "incr/decr final value %u", - testData.m_testValue ); - } - - { - static const unsigned initVal = 1; - static const size_t N = 10; - size_t i; - TestDataTNS_UIntT testData = { 0, N, N }; - epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, - "set/get %u", testData.m_testIterationsSet ); - epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "set/get %u", testData.m_testIterationsNotSet ); - epicsAtomicSetUIntT ( & testData.m_testValue, initVal ); - testOk ( epicsAtomicGetUIntT ( & testData.m_testValue ) == initVal, - "PtrT set/get %u", testData.m_testValue ); - for ( i = 0u; i < N; i++ ) { - epicsThreadCreate ( "tns", - 50, stackSize, tns_UIntT, & testData ); - } - epicsAtomicSetUIntT ( & testData.m_testValue, 0u ); - while ( testData.m_testIterationsSet < N ) { - epicsThreadSleep ( 0.01 ); - } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, - "test and set iterations %u", - testData.m_testIterationsSet ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "test and set not-set tracking = %u", - testData.m_testIterationsNotSet ); - } - - { - static const size_t N = 10; - static char dummy; - size_t i; - TestDataTNS_PtrT testData = { 0, N, N }; - epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, - "set/get %u", testData.m_testIterationsSet ); - epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "SizeT set/get %u", testData.m_testIterationsNotSet ); - epicsAtomicSetPtrT ( & testData.m_testValue, & dummy ); - testOk ( epicsAtomicGetPtrT ( & testData.m_testValue ) == & dummy, - "PtrT set/get %p", testData.m_testValue ); - for ( i = 0u; i < N; i++ ) { - epicsThreadCreate ( "tns", - 50, stackSize, tns_PtrT, & testData ); - } - epicsAtomicSetPtrT ( & testData.m_testValue, 0u ); - while ( testData.m_testIterationsSet < N ) { - epicsThreadSleep ( 0.01 ); - } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, - "test and set iterations %u", - testData.m_testIterationsSet ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "test and set not-set tracking = %u", - testData.m_testIterationsNotSet ); - } - - return testDone(); -} - diff --git a/src/libCom/test/epicsAtomicTest.cpp b/src/libCom/test/epicsAtomicTest.cpp new file mode 100644 index 000000000..ff92a28fa --- /dev/null +++ b/src/libCom/test/epicsAtomicTest.cpp @@ -0,0 +1,238 @@ + +#include +#include + +#include "epicsAtomic.h" +#include "epicsTime.h" +#include "epicsThread.h" +#include "epicsUnitTest.h" +#include "testMain.h" + +using namespace epics; +using namespace atomic; + +template < class T > +struct TestDataIncrDecr { + T m_testValue; + size_t m_testIterations; +}; + +template < class T > +struct TestDataAddSub { + T m_testValue; + size_t m_testIterations; + static const T delta = 17; +}; + +template < class T > +static void incr ( void *arg ) +{ + TestDataIncrDecr < T > * const pTestData = + reinterpret_cast < TestDataIncrDecr < T > * > ( arg ); + increment ( pTestData->m_testValue ); + increment ( pTestData->m_testIterations ); +} + +template < class T > +static void decr ( void *arg ) +{ + TestDataIncrDecr < T > * const pTestData = + reinterpret_cast < TestDataIncrDecr < T > * > ( arg ); + decrement ( pTestData->m_testValue ); + increment ( pTestData->m_testIterations ); +} + + +template < class T > +static void add ( void *arg ) +{ + TestDataAddSub < T > * const pTestData = + reinterpret_cast < TestDataAddSub < T > * > ( arg ); + add ( pTestData->m_testValue, TestDataAddSub < T > :: delta ); + increment ( pTestData->m_testIterations ); +} + +template < class T > +static void sub ( void *arg ) +{ + TestDataAddSub < T > * const pTestData = + reinterpret_cast < TestDataAddSub < T > * > ( arg ); + subtract ( pTestData->m_testValue, TestDataAddSub < T > :: delta ); + increment ( pTestData->m_testIterations ); +} + +template < class T > +struct TestDataCAS { + T m_testValue; + size_t m_testIterationsSet; + size_t m_testIterationsNotSet; +}; + +int isModulo ( size_t N, size_t n ) +{ + return ( n % N ) == 0u; +} + +template < class T > +static T trueValue (); +template < class T > +static T falseValue (); + +// int +template <> +inline int trueValue < int > () { return 1; } + +template <> +inline int falseValue < int > () { return 0; } + +// size_t +template <> +inline size_t trueValue < size_t > () { return 1u; } + +template <> +inline size_t falseValue < size_t > () { return 0u; } + +// EpicsAtomicPtrT +template <> +inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > () +{ static char c; return & c; } + +template <> +inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > () +{ return 0u; } + +template < class T > +static void cas ( void *arg ) +{ + TestDataCAS < T > * const pTestData = + reinterpret_cast < TestDataCAS < T > * > ( arg ); + /* + * intentionally waste cpu and maximize + * contention for the shared data + */ + increment ( pTestData->m_testIterationsNotSet ); + while ( ! compareAndSwap ( pTestData->m_testValue, + falseValue < T > (), + trueValue < T > () ) ) { + } + decrement ( pTestData->m_testIterationsNotSet ); + set ( pTestData->m_testValue, falseValue < T > () ); + increment ( pTestData->m_testIterationsSet ); +} + +template < class T > +void testIncrDecr () +{ + static const size_t N = 100; + static const T NT = static_cast < T > ( N ); + + const unsigned int stackSize = + epicsThreadGetStackSize ( epicsThreadStackSmall ); + + TestDataIncrDecr < T > testData = { 0, N }; + set ( testData.m_testValue, NT ); + testOk ( get ( testData.m_testValue ) == NT, + "set/get %u", testData.m_testValue ); + set ( testData.m_testIterations, 0u ); + testOk ( get ( testData.m_testIterations ) == 0u, + "set/get %u", testData.m_testIterations ); + for ( size_t i = 0u; i < N; i++ ) { + epicsThreadCreate ( "incr", + 50, stackSize, incr < T >, & testData ); + epicsThreadCreate ( "decr", + 50, stackSize, decr < T >, & testData ); + } + while ( testData.m_testIterations < 2 * N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( get ( testData.m_testIterations ) == 2 * N, + "incr/decr iterations %u", + testData.m_testIterations ); + testOk ( get ( testData.m_testValue ) == NT, + "incr/decr final value %u", + testData.m_testValue ); +} + +template < class T > +void testAddSub () +{ + static const size_t N = 100; + static const T NDT = TestDataAddSub < T > :: delta * + static_cast < T > ( N ); + + const unsigned int stackSize = + epicsThreadGetStackSize ( epicsThreadStackSmall ); + + TestDataIncrDecr < T > testData = { 0, N }; + set ( testData.m_testValue, NDT ); + testOk ( get ( testData.m_testValue ) == NDT, + "set/get %u", testData.m_testValue ); + set ( testData.m_testIterations, 0u ); + testOk ( get ( testData.m_testIterations ) == 0u, + "set/get %u", testData.m_testIterations ); + for ( size_t i = 0u; i < N; i++ ) { + epicsThreadCreate ( "add", + 50, stackSize, add < T >, & testData ); + epicsThreadCreate ( "sub", + 50, stackSize, sub < T >, & testData ); + } + while ( testData.m_testIterations < 2 * N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( get ( testData.m_testIterations ) == 2 * N, + "add/sub iterations %u", + testData.m_testIterations ); + testOk ( get ( testData.m_testValue ) == NDT, + "add/sub final value %u", + testData.m_testValue ); +} + +template < class T > +void testCAS () +{ + static const size_t N = 10; + + const unsigned int stackSize = + epicsThreadGetStackSize ( epicsThreadStackSmall ); + + TestDataCAS < T > testData = { 0, N, N }; + set ( testData.m_testIterationsSet, 0 ); + testOk ( get ( testData.m_testIterationsSet ) == 0u, + "set/get %u", testData.m_testIterationsSet ); + set ( testData.m_testIterationsNotSet, 0 ); + testOk ( get ( testData.m_testIterationsNotSet ) == 0u, + "set/get %u", testData.m_testIterationsNotSet ); + set ( testData.m_testValue, trueValue < T > () ); + testOk ( get ( testData.m_testValue ) == trueValue < T > (), + "set/get a true value" ); + for ( size_t i = 0u; i < N; i++ ) { + epicsThreadCreate ( "tns", + 50, stackSize, cas < T >, & testData ); + } + set ( testData.m_testValue, falseValue < T > () ); + while ( testData.m_testIterationsSet < N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( get ( testData.m_testIterationsSet ) == N, + "test and set iterations %u", + testData.m_testIterationsSet ); + testOk ( get ( testData.m_testIterationsNotSet ) == 0u, + "test and set not-set tracking = %u", + testData.m_testIterationsNotSet ); +} + +MAIN ( osiAtomicTest ) +{ + + testPlan ( 31 ); + + testIncrDecr < int > (); + testIncrDecr < size_t > (); + testAddSub < int > (); + testAddSub < size_t > (); + testCAS < int > (); + testCAS < size_t > (); + testCAS < EpicsAtomicPtrT > (); + + return testDone (); +} From 734ea0789a8f4ee1ec1c0a4438a502e79743925b Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 30 Aug 2011 09:01:08 -0600 Subject: [PATCH 47/61] fixed vxWorks jumbled ifdef --- src/libCom/osi/os/WIN32/epicsAtomicMS.h | 444 ++++++++++----------- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 5 +- 2 files changed, 226 insertions(+), 223 deletions(-) diff --git a/src/libCom/osi/os/WIN32/epicsAtomicMS.h b/src/libCom/osi/os/WIN32/epicsAtomicMS.h index bab1da4a4..14d2c9bac 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicMS.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicMS.h @@ -1,222 +1,222 @@ - -/*************************************************************************\ -* Copyright (c) 2011 LANS LLC, as Operator of -* Los Alamos National Laboratory. -* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author Jeffrey O. Hill - * johill@lanl.gov - */ - -#ifndef epicsAtomicMS_h -#define epicsAtomicMS_h - -#include "epicsAssert.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef EPICS_ATOMIC_INCR_INTT -#define EPICS_ATOMIC_INCR_INTT -EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) -{ - STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); - MS_LONG * const pTarg = ( MS_LONG * ) pTarget; - return MS_InterlockedIncrement ( pTarg ); -} -#endif - -#ifndef EPICS_ATOMIC_DECR_INTT -#define EPICS_ATOMIC_DECR_INTT -EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) -{ - STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); - MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); - return MS_InterlockedDecrement ( pTarg ); -} -#endif - -#ifndef EPICS_ATOMIC_ADD_INTT -#define EPICS_ATOMIC_ADD_INTT -EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) -{ - STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); - MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); - /* we dont use InterlockedAdd because only latest windows is supported */ - return delta + ( int ) MS_InterlockedExchangeAdd ( pTarg, - ( MS_LONG ) delta ); -} -#endif - -#ifndef EPICS_ATOMIC_CAS_INTT -#define EPICS_ATOMIC_CAS_INTT -EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, - int oldVal, int newVal ) -{ - STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); - MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); - return (int) MS_InterlockedCompareExchange ( pTarg, - (MS_LONG) newVal, (MS_LONG) oldVal ); -} -#endif - -#if ! defined ( MS_ATOMIC_64 ) - -/* - * necessary for next three functions - * - * looking at the MS documentation it appears that they will - * keep type long the same size as an int on 64 bit builds - */ -STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( size_t ) ); - -#ifndef EPICS_ATOMIC_INCR_SIZET -#define EPICS_ATOMIC_INCR_SIZET -EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - MS_LONG * const pTarg = ( MS_LONG * ) pTarget; - return MS_InterlockedIncrement ( pTarg ); -} -#endif - -#ifndef EPICS_ATOMIC_DECR_SIZET -#define EPICS_ATOMIC_DECR_SIZET -EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); - return MS_InterlockedDecrement ( pTarg ); -} -#endif - -#ifndef EPICS_ATOMIC_ADD_SIZET -#define EPICS_ATOMIC_ADD_SIZET -EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, - size_t delta ) -{ - MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); - /* we dont use InterlockedAdd because only latest windows is supported */ - return delta + ( size_t ) MS_InterlockedExchangeAdd ( pTarg, - ( MS_LONG ) delta ); -} -#endif - -#ifndef EPICS_ATOMIC_SUB_SIZET -#define EPICS_ATOMIC_SUB_SIZET -EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) -{ - MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); - MS_LONG ldelta = (MS_LONG) delta; - /* we dont use InterlockedAdd because only latest windows is supported */ - return ( ( size_t ) MS_InterlockedExchangeAdd ( pTarg, -ldelta ) ) - delta; -} -#endif - -#ifndef EPICS_ATOMIC_CAS_SIZET -#define EPICS_ATOMIC_CAS_SIZET -EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( - size_t * pTarget, - size_t oldVal, size_t newVal ) -{ - MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); - return (size_t) MS_InterlockedCompareExchange ( pTarg, - (MS_LONG) newVal, (MS_LONG) oldVal ); -} -#endif - -#ifndef EPICS_ATOMIC_CAS_PTRT -#define EPICS_ATOMIC_CAS_PTRT -EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( - EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); - return (EpicsAtomicPtrT) MS_InterlockedCompareExchange ( pTarg, - (MS_LONG) newVal, (MS_LONG) oldVal ); -} -#endif - -#else /* ! MS_ATOMIC_64 */ - -/* - * necessary for next three functions - */ -STATIC_ASSERT ( sizeof ( MS_LONGLONG ) == sizeof ( size_t ) ); - -#ifndef EPICS_ATOMIC_INCR_SIZET -#define EPICS_ATOMIC_INCR_SIZET -EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) pTarget; - return ( size_t ) MS_InterlockedIncrement64 ( pTarg ); -} -#endif - -#ifndef EPICS_ATOMIC_DECR_SIZET -#define EPICS_ATOMIC_DECR_SIZET -EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); - return ( size_t ) MS_InterlockedDecrement64 ( pTarg ); -} -#endif - -#ifndef EPICS_ATOMIC_ADD_SIZET -#define EPICS_ATOMIC_ADD_SIZET -EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) -{ - MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); - /* we dont use InterlockedAdd64 because only latest windows is supported */ - return delta + ( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, - ( MS_LONGLONG ) delta ); -} -#endif - -#ifndef EPICS_ATOMIC_SUB_SIZET -#define EPICS_ATOMIC_SUB_SIZET -EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) -{ - MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); - MS_LONGLONG ldelta = (MS_LONGLONG) delta; - /* we dont use InterlockedAdd64 because only latest windows is supported */ - return (( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, -ldelta )) - delta; -} -#endif - -#ifndef EPICS_ATOMIC_CAS_SIZET -#define EPICS_ATOMIC_CAS_SIZET -EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, - size_t oldVal, size_t newVal ) -{ - MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); - return (size_t) MS_InterlockedCompareExchange64 ( pTarg, - (MS_LONGLONG) newVal, - (MS_LONGLONG) oldVal ); -} -#endif - -#ifndef EPICS_ATOMIC_CAS_PTRT -#define EPICS_ATOMIC_CAS_PTRT -EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( - EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); - return (EpicsAtomicPtrT) MS_InterlockedCompareExchange64 ( pTarg, - (MS_LONGLONG) newVal, (MS_LONGLONG) oldVal ); -} -#endif - -#endif /* ! MS_ATOMIC_64 */ - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif /* __cplusplus */ - -#endif /* ifdef epicsAtomicMS_h */ - + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomicMS_h +#define epicsAtomicMS_h + +#include "epicsAssert.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef EPICS_ATOMIC_INCR_INTT +#define EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) pTarget; + return MS_InterlockedIncrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_INTT +#define EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return MS_InterlockedDecrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_ADD_INTT +#define EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + /* we dont use InterlockedAdd because only latest windows is supported */ + return delta + ( int ) MS_InterlockedExchangeAdd ( pTarg, + ( MS_LONG ) delta ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_INTT +#define EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return (int) MS_InterlockedCompareExchange ( pTarg, + (MS_LONG) newVal, (MS_LONG) oldVal ); +} +#endif + +#if ! defined ( MS_ATOMIC_64 ) + +/* + * necessary for next three functions + * + * looking at the MS documentation it appears that they will + * keep type long the same size as an int on 64 bit builds + */ +STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( size_t ) ); + +#ifndef EPICS_ATOMIC_INCR_SIZET +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) pTarget; + return MS_InterlockedIncrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_SIZET +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return MS_InterlockedDecrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_ADD_SIZET +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, + size_t delta ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + /* we dont use InterlockedAdd because only latest windows is supported */ + return delta + ( size_t ) MS_InterlockedExchangeAdd ( pTarg, + ( MS_LONG ) delta ); +} +#endif + +#ifndef EPICS_ATOMIC_SUB_SIZET +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + MS_LONG ldelta = (MS_LONG) delta; + /* we dont use InterlockedAdd because only latest windows is supported */ + return ( ( size_t ) MS_InterlockedExchangeAdd ( pTarg, -ldelta ) ) - delta; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_SIZET +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( + size_t * pTarget, + size_t oldVal, size_t newVal ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return (size_t) MS_InterlockedCompareExchange ( pTarg, + (MS_LONG) newVal, (MS_LONG) oldVal ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_PTRT +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return (EpicsAtomicPtrT) MS_InterlockedCompareExchange ( pTarg, + (MS_LONG) newVal, (MS_LONG) oldVal ); +} +#endif + +#else /* ! MS_ATOMIC_64 */ + +/* + * necessary for next three functions + */ +STATIC_ASSERT ( sizeof ( MS_LONGLONG ) == sizeof ( size_t ) ); + +#ifndef EPICS_ATOMIC_INCR_SIZET +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) pTarget; + return ( size_t ) MS_InterlockedIncrement64 ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_SIZET +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + return ( size_t ) MS_InterlockedDecrement64 ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_ADD_SIZET +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + /* we dont use InterlockedAdd64 because only latest windows is supported */ + return delta + ( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, + ( MS_LONGLONG ) delta ); +} +#endif + +#ifndef EPICS_ATOMIC_SUB_SIZET +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + MS_LONGLONG ldelta = (MS_LONGLONG) delta; + /* we dont use InterlockedAdd64 because only latest windows is supported */ + return (( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, -ldelta )) - delta; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_SIZET +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldVal, size_t newVal ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + return (size_t) MS_InterlockedCompareExchange64 ( pTarg, + (MS_LONGLONG) newVal, + (MS_LONGLONG) oldVal ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_PTRT +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + return (EpicsAtomicPtrT) MS_InterlockedCompareExchange64 ( pTarg, + (MS_LONGLONG) newVal, (MS_LONGLONG) oldVal ); +} +#endif + +#endif /* ! MS_ATOMIC_64 */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#endif /* ifdef epicsAtomicMS_h */ + diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index c54a2b4c2..4ce35b975 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -98,7 +98,10 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta ); return delta + ( size_t ) oldVal; -} #endif #ifndef EPICS_ATOMIC_SUB_SIZET +} +#endif + +#ifndef EPICS_ATOMIC_SUB_SIZET #define EPICS_ATOMIC_SUB_SIZET EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) { From f3ca4f16016c6e70b9ae41e908de27c5b388aadd Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 30 Aug 2011 09:27:40 -0600 Subject: [PATCH 48/61] fixed test count From ad669d6ece4066793776f4a6d9826d9f0287524f Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 30 Aug 2011 10:29:56 -0600 Subject: [PATCH 49/61] fixed wrong return type old vxWorks epicsAtomicUnlock --- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 4ce35b975..3c177dbe6 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -217,7 +217,7 @@ EPICS_ATOMIC_INLINE void epicsAtomicLock ( EpicsAtomicLockKey * pKey ) pKey->m_key = intLock (); } -EPICS_ATOMIC_INLINE EpicsAtomicLockKey epicsAtomicUnlock ( EpicsAtomicLockKey * pKey ) +EPICS_ATOMIC_INLINE void epicsAtomicUnlock ( EpicsAtomicLockKey * pKey ) { intUnlock ( pKey->m_key ); } From 43fa23bba615c2f44e278f4c31ebcb3d08f06bf2 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 30 Aug 2011 10:49:52 -0600 Subject: [PATCH 50/61] fixed vxWorks name for epicsAtomicTest --- src/libCom/test/epicsAtomicTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/test/epicsAtomicTest.cpp b/src/libCom/test/epicsAtomicTest.cpp index ff92a28fa..bdcee8b71 100644 --- a/src/libCom/test/epicsAtomicTest.cpp +++ b/src/libCom/test/epicsAtomicTest.cpp @@ -221,7 +221,7 @@ void testCAS () testData.m_testIterationsNotSet ); } -MAIN ( osiAtomicTest ) +MAIN ( epicsAtomicTest ) { testPlan ( 31 ); From 798f1f2ace653b610a9375031a4a665d14bc3c06 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 30 Aug 2011 13:34:17 -0600 Subject: [PATCH 51/61] fixed word missing from vxWorks specific read and write memory barrier functions --- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 3c177dbe6..11a3d4ae1 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -35,7 +35,7 @@ extern "C" { #ifndef EPICS_READ_MEMORY_BARRIER #define EPICS_READ_MEMORY_BARRIER -EPICS_ATOMIC_INLINE void epicsReadMemoryBarrier () +EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () { VX_MEM_BARRIER_R (); } @@ -43,7 +43,7 @@ EPICS_ATOMIC_INLINE void epicsReadMemoryBarrier () #ifndef EPICS_WRITE_MEMORY_BARRIER #define EPICS_WRITE_MEMORY_BARRIER -EPICS_ATOMIC_INLINE void epicsWriteMemoryBarrier () +EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () { VX_MEM_BARRIER_W (); } From 5f096a8b8060b7d21db9a1e7faff58d12a9917fb Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 30 Aug 2011 14:04:36 -0600 Subject: [PATCH 52/61] fixed epics atomic read memory barrier name - old versions of vxWorks --- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 11a3d4ae1..c616481e0 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -229,7 +229,7 @@ EPICS_ATOMIC_INLINE void epicsAtomicUnlock ( EpicsAtomicLockKey * pKey ) * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system * (we are not protecting against multiple access to memory mapped IO) */ -EPICS_ATOMIC_INLINE void epicsReadMemoryBarrier () {} +EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () {} #endif #ifndef EPICS_WRITE_MEMORY_BARRIER @@ -238,7 +238,7 @@ EPICS_ATOMIC_INLINE void epicsReadMemoryBarrier () {} * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system * (we are not protecting against multiple access to memory mapped IO) */ -EPICS_ATOMIC_INLINE void epicsWriteMemoryBarrier () {} +EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () {} #endif #ifdef __cplusplus From 3bae2a470fb7bfff156b23f3b8da8f8c19d57e4c Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 30 Aug 2011 14:46:24 -0600 Subject: [PATCH 53/61] fixed names on redefinition protection macros for vxWorks --- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index c616481e0..c52d991b0 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -33,16 +33,16 @@ extern "C" { #endif /* __cplusplus */ -#ifndef EPICS_READ_MEMORY_BARRIER -#define EPICS_READ_MEMORY_BARRIER +#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER +#define EPICS_ATOMIC_READ_MEMORY_BARRIER EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () { VX_MEM_BARRIER_R (); } #endif -#ifndef EPICS_WRITE_MEMORY_BARRIER -#define EPICS_WRITE_MEMORY_BARRIER +#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER +#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () { VX_MEM_BARRIER_W (); @@ -223,8 +223,8 @@ EPICS_ATOMIC_INLINE void epicsAtomicUnlock ( EpicsAtomicLockKey * pKey ) } #endif -#ifndef EPICS_READ_MEMORY_BARRIER -#define EPICS_READ_MEMORY_BARRIER +#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER +#define EPICS_ATOMIC_READ_MEMORY_BARRIER /* * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system * (we are not protecting against multiple access to memory mapped IO) @@ -232,8 +232,8 @@ EPICS_ATOMIC_INLINE void epicsAtomicUnlock ( EpicsAtomicLockKey * pKey ) EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () {} #endif -#ifndef EPICS_WRITE_MEMORY_BARRIER -#define EPICS_WRITE_MEMORY_BARRIER +#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER +#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER /* * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system * (we are not protecting against multiple access to memory mapped IO) From f5c374c556ad12f60cc337dbdd5542e475843b94 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Thu, 1 Sep 2011 11:25:53 -0600 Subject: [PATCH 54/61] o improved comments o dont include epicsAtomicOSD.h from any of the implementations of epicsAtomicCD.h unless the compiler has support for an inline keyword o removed superfluous ifdef on EPICS_ATOMIC_INLINE all versions of epicsAtomicDefault.h and epicsAtomicOSD.h o In the implementations of epicsAtomicOSD.cpp if EPICS_ATOMIC_INLINE isnt defined define it to be empty and then include epicsAtomicOSD.h o fixing some compile time issues for solaris version of epicsAtomicOSD.h (so that Janet can run another compile on that os) --- src/libCom/osi/compiler/clang/epicsAtomicCD.h | 4 ++ .../osi/compiler/default/epicsAtomicCD.h | 9 ++++- src/libCom/osi/compiler/msvc/epicsAtomicCD.h | 2 +- .../osi/compiler/solStudio/epicsAtomicCD.h | 4 ++ src/libCom/osi/epicsAtomic.h | 4 +- src/libCom/osi/epicsAtomicDefault.h | 8 ---- src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp | 4 +- src/libCom/osi/os/WIN32/epicsAtomicOSD.h | 6 +-- src/libCom/osi/os/posix/epicsAtomicOSD.cpp | 17 ++------ src/libCom/osi/os/posix/epicsAtomicOSD.h | 4 -- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 40 ++++++++++++++----- src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp | 5 +-- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 4 -- 13 files changed, 57 insertions(+), 54 deletions(-) diff --git a/src/libCom/osi/compiler/clang/epicsAtomicCD.h b/src/libCom/osi/compiler/clang/epicsAtomicCD.h index 54465d6f4..00fa24e4b 100644 --- a/src/libCom/osi/compiler/clang/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/clang/epicsAtomicCD.h @@ -22,6 +22,10 @@ # define EPICS_ATOMIC_INLINE __inline__ #endif +/* + * we have an inline keyword so we can proceed + * with an os specific inline instantiation + */ #include "epicsAtomicOSD.h" #endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/default/epicsAtomicCD.h b/src/libCom/osi/compiler/default/epicsAtomicCD.h index d07dfb24f..3ca260759 100644 --- a/src/libCom/osi/compiler/default/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/default/epicsAtomicCD.h @@ -18,8 +18,13 @@ #if __STDC_VERSION__ >= 199901L || defined ( __cplusplus ) # define EPICS_ATOMIC_INLINE inline + /* + * We have already defined the public interface in epicsAtomic.h + * so there is nothing more to implement if there isnt an inline + * keyword available. Otherwise, if we have an inline keyword + * we will proceed with an os specific inline implementation. + */ +# include "epicsAtomicOSD.h" #endif -#include "epicsAtomicOSD.h" - #endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index ca9295f73..f834f0405 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -114,7 +114,7 @@ EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () /* * if unavailable as an intrinsic we will try - * for os specific solution + * for os specific inline solution */ #include "epicsAtomicOSD.h" diff --git a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h index e247a5e49..60083cf71 100644 --- a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h @@ -22,6 +22,10 @@ # define EPICS_ATOMIC_INLINE __inline #endif +/* + * we have an inline keyword so we can proceed + * with an os specific inline instantiation + */ #include "epicsAtomicOSD.h" #endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index 436da7bd0..c4ff6d65f 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -97,9 +97,9 @@ epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( * options for inline compiler instrinsic or os specific * implementations of the above function prototypes * - * its importnat for certaiin compiler to define the + * for some of the compilers we must define the * inline functions before they get used in the c++ - * code below + * inine functions below */ #include "epicsAtomicCD.h" diff --git a/src/libCom/osi/epicsAtomicDefault.h b/src/libCom/osi/epicsAtomicDefault.h index ff1f91114..ec0975daf 100644 --- a/src/libCom/osi/epicsAtomicDefault.h +++ b/src/libCom/osi/epicsAtomicDefault.h @@ -16,12 +16,6 @@ #ifndef epicsAtomicDefault_h #define epicsAtomicDefault_h -/* - * EPICS_ATOMIC_INLINE might be defined, but empty for an out-of-line - * instantiation - */ -#ifdef EPICS_ATOMIC_INLINE - #ifdef __cpluplus extern "C" { #endif @@ -228,8 +222,6 @@ EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( } /* end of extern "C" */ #endif -#endif /* EPICS_ATOMIC_INLINE */ - #endif /* epicsAtomicDefault_h */ diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp b/src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp index b7f7b17c2..e3f684e29 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp @@ -16,7 +16,7 @@ // if the compiler is unable to inline then instantiate out-of-line #ifndef EPICS_ATOMIC_INLINE -#define EPICS_ATOMIC_INLINE -#include "epicsAtomic.h" +# define EPICS_ATOMIC_INLINE +# include "epicsAtomicOSD.h" #endif diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index f9378c1c6..00b6cc606 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -40,10 +40,8 @@ # define MS_InterlockedCompareExchange InterlockedCompareExchange64 #endif -#ifdef EPICS_ATOMIC_INLINE -# include "epicsAtomicMS.h" -# include "epicsAtomicDefault.h" -#endif +#include "epicsAtomicMS.h" +#include "epicsAtomicDefault.h" #endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp index 2fb06c36f..a8173f894 100644 --- a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp @@ -7,31 +7,22 @@ \*************************************************************************/ /* - * Author Jeffrey O. Hill + * Author: Jeffrey O. Hill * johill@lanl.gov */ -#define epicsExportSharedSymbols -#include "epicsAtomic.h" - -// if the compiler is unable to inline then instantiate out-of-line -#ifndef EPICS_ATOMIC_INLINE -#define EPICS_ATOMIC_INLINE -#include "epicsAtomic.h" -#endif - -/* Authors: Jeffrey O. Hill */ #include #include #include #define epicsExportSharedSymbols #include "epicsAssert.h" +#include "epicsAtomic.h" // if the compiler is unable to inline then instantiate out-of-line #ifndef EPICS_ATOMIC_INLINE -#define EPICS_ATOMIC_INLINE -#include "epicsAtomic.h" +# define EPICS_ATOMIC_INLINE +# include "epicsAtomicOSD.h" #endif #ifndef EPICS_ATOMIC_LOCK diff --git a/src/libCom/osi/os/posix/epicsAtomicOSD.h b/src/libCom/osi/os/posix/epicsAtomicOSD.h index 5446f23ef..4f14fa39c 100644 --- a/src/libCom/osi/os/posix/epicsAtomicOSD.h +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.h @@ -22,11 +22,7 @@ epicsShareFunc void epicsAtomicWriteMemoryBarrier (); epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * ); epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * ); -#ifdef EPICS_ATOMIC_INLINE - #include "epicsAtomicDefault.h" -#endif /* ifdef EPICS_ATOMIC_INLINE */ - #endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index e377a770b..b591c6b79 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -16,22 +16,22 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#if defined ( EPICS_ATOMIC_INLINE ) +#if defined ( __SunOS_5_10 ) /* * atomic.h exists only in Solaris 10 or higher */ -#if defined ( __SunOS_5_10 ) - #include +#include "epicsAssert.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER #define EPICS_ATOMIC_READ_MEMORY_BARRIER -EPICS_ATOMIC_INLINE int epicsAtomicReadMemoryBarrier () +EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () { membar_consumer (); } @@ -39,7 +39,7 @@ EPICS_ATOMIC_INLINE int epicsAtomicReadMemoryBarrier () #ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER #define EPICS_ATOMIC_WRITE_MEMORY_BARRIER -EPICS_ATOMIC_INLINE int epicsAtomicWriteMemoryBarrier () +EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () { membar_producer (); } @@ -51,19 +51,20 @@ EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, int oldVal, int newVal ) { STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); - return ( int ) atomic_cas_uint ( pTarget, ( unsigned ) oldVal, + unsigned * const pTarg = reinterpret_cast < unsigned * > ( pTarget ); + return ( int ) atomic_cas_uint ( pTarg, ( unsigned ) oldVal, ( unsigned ) newVal ); } #endif #ifndef EPICS_ATOMIC_CAS_SIZET #define EPICS_ATOMIC_CAS_SIZET -EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapSizeT ( +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, size_t oldVal, size_t newVal ) { STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); - void ** ppPtr = (void **) pTarget; + void ** const ppPtr = (void **) pTarget; return ( size_t ) atomic_cas_ptr ( ppPtr, ( void * )oldVal, ( void * )newVal ); } #endif @@ -147,7 +148,7 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, { STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); void ** const pTarg = ( void ** ) ( pTarget ); - ssize_t = sdelta = ( ssize_t ) delta; + ssize_t sdelta = ( ssize_t ) delta; return ( size_t ) atomic_add_ptr_nv ( pTarg, -sdelta ); } #endif @@ -156,11 +157,28 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, } /* end of extern "C" */ #endif /* __cplusplus */ +#else /* ifdef __SunOS_5_10 */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * its less than 5.10 so we forward reference to the out-of-line posix + * pthread lock implementation of epicsAtomicLock and epicsAtomicUnlock + * before including "epicsAtomicDefault.h" + */ +struct EpicsAtomicLockKey {}; +epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * ); +epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * ); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + #endif /* ifdef __SunOS_5_10 */ #include "epicsAtomicDefault.h" -#endif /* if defined ( EPICS_ATOMIC_INLINE ) */ - #endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp index b7f7b17c2..6a9f529a3 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp @@ -16,7 +16,6 @@ // if the compiler is unable to inline then instantiate out-of-line #ifndef EPICS_ATOMIC_INLINE -#define EPICS_ATOMIC_INLINE -#include "epicsAtomic.h" +# define EPICS_ATOMIC_INLINE +# include "epicsAtomicOSD.h" #endif - diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index c52d991b0..2cf981f14 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -15,8 +15,6 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#if defined ( EPICS_ATOMIC_INLINE ) - #include "vxWorks.h" /* obtain the version of vxWorks */ #include "epicsAssert.h" @@ -249,7 +247,5 @@ EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () {} #include "epicsAtomicDefault.h" -#endif /* if defined ( EPICS_ATOMIC_INLINE ) */ - #endif /* epicsAtomicOSD_h */ From c76b800f2a878933faeaee28e03202102c74f160 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Thu, 1 Sep 2011 11:43:14 -0600 Subject: [PATCH 55/61] must ... not .. use the improved c++ casts in c code --- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index b591c6b79..c2d58cf47 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -51,7 +51,7 @@ EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, int oldVal, int newVal ) { STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); - unsigned * const pTarg = reinterpret_cast < unsigned * > ( pTarget ); + unsigned * const pTarg = ( unsigned * ) pTarget; return ( int ) atomic_cas_uint ( pTarg, ( unsigned ) oldVal, ( unsigned ) newVal ); } From 1ff2408ba4d22518bcf7cea494441c7ae1c675cd Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 2 Sep 2011 09:59:03 -0600 Subject: [PATCH 56/61] o hoping that atomic_inc_ptr_nv and atomic_dec_ptr_nv interface definitions will be available if we use sys/atomic.h instead of atomic.h o fixed issue introduced by last revision where definition of lock functions and lock key were not present if its sunos 5.10 or greater (its time consuming to develop code if you can only run the (SUNPRO) compiler indirectly) --- src/libCom/osi/os/posix/epicsAtomicOSD.h | 11 +++++++++-- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 14 ++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/libCom/osi/os/posix/epicsAtomicOSD.h b/src/libCom/osi/os/posix/epicsAtomicOSD.h index 4f14fa39c..76c70cd54 100644 --- a/src/libCom/osi/os/posix/epicsAtomicOSD.h +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.h @@ -17,11 +17,18 @@ #define epicsAtomicOSD_h struct EpicsAtomicLockKey {}; -epicsShareFunc void epicsAtomicReadMemoryBarrier (); -epicsShareFunc void epicsAtomicWriteMemoryBarrier (); + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * ); epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * ); +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + #include "epicsAtomicDefault.h" #endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index c2d58cf47..a890994f1 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -21,7 +21,7 @@ /* * atomic.h exists only in Solaris 10 or higher */ -#include +#include #include "epicsAssert.h" @@ -157,18 +157,14 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, } /* end of extern "C" */ #endif /* __cplusplus */ -#else /* ifdef __SunOS_5_10 */ +#endif /* ifdef __SunOS_5_10 */ + +struct EpicsAtomicLockKey {}; #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/* - * its less than 5.10 so we forward reference to the out-of-line posix - * pthread lock implementation of epicsAtomicLock and epicsAtomicUnlock - * before including "epicsAtomicDefault.h" - */ -struct EpicsAtomicLockKey {}; epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * ); epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * ); @@ -176,8 +172,6 @@ epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * ); } /* end of extern "C" */ #endif /* __cplusplus */ -#endif /* ifdef __SunOS_5_10 */ - #include "epicsAtomicDefault.h" #endif /* epicsAtomicOSD_h */ From fd10e7751886f13a1953ba6cc9fbaee82c404dc4 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 2 Sep 2011 18:18:46 -0600 Subject: [PATCH 57/61] o hopefully fixed missing functions with sunos 5.10 or higher o removed unused trash files which somehow reappeared after rebase --- src/libCom/osi/epicsAtomicLocked.cpp | 154 --------------------- src/libCom/osi/epicsAtomicLocked.h | 118 ---------------- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 29 ++-- 3 files changed, 12 insertions(+), 289 deletions(-) delete mode 100644 src/libCom/osi/epicsAtomicLocked.cpp delete mode 100644 src/libCom/osi/epicsAtomicLocked.h diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp deleted file mode 100644 index bf948ccc8..000000000 --- a/src/libCom/osi/epicsAtomicLocked.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2011 LANS LLC, as Operator of -* Los Alamos National Laboratory. -* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author Jeffrey O. Hill - * johill@lanl.gov - * - * Provide a global mutex version of the atomic functions for when - * we dont have more efficent OS primitives or compiler intriniscs - * to use instead. - * - * We implement these mutex-based primitives upon the libCom private - * interface epicsMutexOsdXxxx because, in libCom, it is convenient - * to make this a standalone primitive upon which we can implement - * epicsMutex. - */ - -#define epicsExportSharedSymbols -#include "epicsAtomic.h" -#include "epicsThread.h" -#include "epicsMutex.h" - -namespace { - -class AtomicGuard { -public: - AtomicGuard (); - ~AtomicGuard (); -private: - static epicsMutexOSD * m_pMutex; - static epicsThreadOnceId m_onceFlag; - static void m_once ( void * ); -}; - -// -// c++ 0x specifies the behavior for concurrent -// access to block scope statics but some compiler -// writers, lacking clear guidance in the earlier -// c++ standards, curiously implement thread unsafe -// block static variables despite ensuring for -// proper multithreaded behavior for many other -// parst of the compiler infrastructure such as -// runtime support for exception handling -// -// since this is potentially used by the implementation -// of staticInstance we cant use it here and must use -// epicsThreadOnce despite its perfomance pentalty -// -// using epicsThreadOnce here (at this time) increases -// the overhead of AtomicGuard by as much as 100% -// -epicsMutexOSD * AtomicGuard :: m_pMutex = 0; -epicsThreadOnceId AtomicGuard :: m_onceFlag = EPICS_THREAD_ONCE_INIT; - -void AtomicGuard :: m_once ( void * ) -{ - m_pMutex = epicsMutexOsdCreate (); -} - -inline AtomicGuard :: AtomicGuard () -{ - - epicsThreadOnce ( & m_onceFlag, m_once, 0 ); - const int status = epicsMutexOsdLock ( m_pMutex ); - assert ( status == epicsMutexLockOK ); -} - -inline AtomicGuard :: ~AtomicGuard () -{ - epicsMutexOsdUnlock ( m_pMutex ); -} - -} // end of anonymous namespace - -extern "C" { - -size_t epicsLockedIncrSizeT ( size_t * pTarget ) -{ - AtomicGuard atomicGuard; - return ++(*pTarget); -} - -size_t epicsLockedDecrSizeT ( size_t * pTarget ) -{ - AtomicGuard atomicGuard; - return --(*pTarget); -} - -void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ) -{ - AtomicGuard atomicGuard; - *pTarget = newVal; -} - -void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ) -{ - AtomicGuard atomicGuard; - *pTarget = newVal; -} - -void epicsLockedSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - AtomicGuard atomicGuard; - *pTarget = newVal; -} - -unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) -{ - AtomicGuard atomicGuard; - return *pTarget; -} - -size_t epicsLockedGetSizeT ( const size_t * pTarget ) -{ - AtomicGuard atomicGuard; - return *pTarget; -} - -EpicsAtomicPtrT epicsLockedGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - AtomicGuard atomicGuard; - return *pTarget; -} - -unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldval, unsigned newval ) -{ - AtomicGuard atomicGuard; - const unsigned cur = *pTarget; - if ( cur == oldval ) { - *pTarget = newval; - } - return cur; -} - -EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) -{ - AtomicGuard atomicGuard; - const EpicsAtomicPtrT cur = *pTarget; - if ( cur == oldval ) { - *pTarget = newval; - } - return cur; -} - -} // end of extern "C" - diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h deleted file mode 100644 index 4707d66f9..000000000 --- a/src/libCom/osi/epicsAtomicLocked.h +++ /dev/null @@ -1,118 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2011 LANS LLC, as Operator of -* Los Alamos National Laboratory. -* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author Jeffrey O. Hill - * johill@lanl.gov - */ - -// -// The epicsAtomicXxxxx functions herein are implemented with C++ but directly -// callable by C code, and therefore they must not be instantiated inline. -// Therefore, this isnt a traditional header file because it has function -// definitions that are not inline, and must therefore be included by only -// one module in the executable - typically this is the epicsAtomicOSD -// c++ source file. These out-of-line function definitions are placed in a -// header file so that there is potential code reuse when instantiating for -// a specific OS. An alternative option would have been to place these -// function definitions in a OS type conditionally compiled source file -// but this wasnt done because I suspect that selecting the posix version -// would require a proliferation of "SRCS_XXXX += xxx.cpp" in the libCom -// Makefile for every variety of Unix (a maintenance headache when new -// varieties of UNIX are configured). -// -// Aee also the comments in epicsAtomicGuard header. -// - -#ifndef epicsAtomicLocked_h -#define epicsAtomicLocked_h - -#ifndef __cplusplus -# error epicsAtomicLocked.h is intended only for use only by C++ code -#endif - -#include "epicsAtomic.h" // always cross check the function prototypes -#include "epicsAtomicGuard.h" - -extern "C" { - -size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - AtomicGuard atomicGuard; - return ++(*pTarget); -} - -size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - AtomicGuard atomicGuard; - return --(*pTarget); -} - -void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - AtomicGuard atomicGuard; - *pTarget = newVal; -} - -void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) -{ - AtomicGuard atomicGuard; - *pTarget = newVal; -} - -void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - AtomicGuard atomicGuard; - *pTarget = newVal; -} - -unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) -{ - AtomicGuard atomicGuard; - return *pTarget; -} - -size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - AtomicGuard atomicGuard; - return *pTarget; -} - -EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - AtomicGuard atomicGuard; - return *pTarget; -} - -unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldval, unsigned newval ) -{ - AtomicGuard atomicGuard; - const unsigned cur = *pTarget; - if ( cur == oldval ) { - *pTarget = newval; - } - return cur; -} - -EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) -{ - AtomicGuard atomicGuard; - const EpicsAtomicPtrT cur = *pTarget; - if ( cur == oldval ) { - *pTarget = newval; - } - return cur; -} - -} // end of extern "C" - -#endif /* epicsAtomicLocked_h */ - diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index a890994f1..4987ab4d2 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -21,7 +21,7 @@ /* * atomic.h exists only in Solaris 10 or higher */ -#include +#include #include "epicsAssert.h" @@ -63,9 +63,8 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, size_t oldVal, size_t newVal ) { - STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); - void ** const ppPtr = (void **) pTarget; - return ( size_t ) atomic_cas_ptr ( ppPtr, ( void * )oldVal, ( void * )newVal ); + STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) ); + return atomic_cas_ulong ( pTarget, oldVal, newVal ); } #endif @@ -94,9 +93,8 @@ EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) #define EPICS_ATOMIC_INCR_SIZET EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); - void ** const ppTarg = ( void ** ) ( pTarget ); - return ( size_t ) atomic_inc_ptr_nv ( ppTarg ); + STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) ); + return atomic_inc_ulong_nv ( pTarget ); } #endif @@ -114,9 +112,8 @@ EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) #define EPICS_ATOMIC_DECR_SIZET EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); - void ** const pTarg = ( void ** ) ( pTarget ); - return ( size_t ) atomic_dec_ptr_nv ( pTarg ); + STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) ); + return atomic_dec_ulong_nv ( pTarget ); } #endif @@ -135,9 +132,8 @@ EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) { - STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); - void ** const pTarg = ( void ** ) ( pTarget ); - return ( size_t ) atomic_add_ptr_nv ( pTarg, ( ssize_t ) delta ); + STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) ); + return atomic_add_long_nv ( pTarget, ( long ) delta ); } #endif @@ -146,10 +142,9 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) { - STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); - void ** const pTarg = ( void ** ) ( pTarget ); - ssize_t sdelta = ( ssize_t ) delta; - return ( size_t ) atomic_add_ptr_nv ( pTarg, -sdelta ); + STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) ); + long sdelta = ( long ) delta; + return atomic_add_long_nv ( pTarget, -sdelta ); } #endif From 841978e8c84a1b85fb25027f22ae60b4ce5fe8f0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 6 Sep 2011 10:33:56 -0500 Subject: [PATCH 58/61] Remove epicsAtomicLocked.{h,cpp} from Makefile too. --- src/libCom/osi/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index c8809166c..9a0c80c99 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -46,7 +46,6 @@ INC += osdWireFormat.h INC += osdWireConfig.h INC += epicsAtomic.h INC += epicsAtomicDefault.h -INC += epicsAtomicLocked.h INC += epicsAtomicOSD.h INC += epicsAtomicCD.h INC += epicsEndian.h @@ -67,7 +66,6 @@ Com_SRCS += epicsEvent.cpp Com_SRCS += epicsTime.cpp Com_SRCS += epicsMessageQueue.cpp Com_SRCS += epicsMath.cpp -Com_SRCS += epicsAtomicLocked.cpp Com_SRCS += epicsAtomicOSD.cpp Com_SRCS += epicsGeneralTime.c From 57953e6e24c8b7c9f2a7fbaf1d4d631dc7043967 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 6 Sep 2011 18:51:04 -0600 Subject: [PATCH 59/61] fixed sunos compiler issue (I dont have sunos 5.10 here) --- src/libCom/osi/os/solaris/epicsAtomicOSD.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 4987ab4d2..5845b6b39 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -64,7 +64,8 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t oldVal, size_t newVal ) { STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) ); - return atomic_cas_ulong ( pTarget, oldVal, newVal ); + ulong_t * const pTarg = ( ulong_t * ) pTarget; + return ( size_t ) atomic_cas_ulong ( pTarg, oldVal, newVal ); } #endif @@ -94,7 +95,8 @@ EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) ); - return atomic_inc_ulong_nv ( pTarget ); + ulong_t * const pTarg = ( ulong_t * ) pTarget; + return ( size_t ) atomic_inc_ulong_nv ( pTarg ); } #endif @@ -113,7 +115,8 @@ EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) ); - return atomic_dec_ulong_nv ( pTarget ); + ulong_t * const pTarg = ( ulong_t * ) pTarget; + return ( size_t ) atomic_dec_ulong_nv ( pTarg ); } #endif @@ -133,7 +136,8 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) { STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) ); - return atomic_add_long_nv ( pTarget, ( long ) delta ); + ulong_t * const pTarg = ( ulong_t * ) pTarget; + return ( size_t ) atomic_add_long_nv ( pTarg, ( long ) delta ); } #endif @@ -143,8 +147,9 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) { STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) ); + ulong_t * const pTarg = ( ulong_t * ) pTarget; long sdelta = ( long ) delta; - return atomic_add_long_nv ( pTarget, -sdelta ); + return ( size_t ) atomic_add_long_nv ( pTarg, -sdelta ); } #endif From 26757f53173b2498e7cd4ad472e33b55f762ed22 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 7 Sep 2011 10:59:11 -0500 Subject: [PATCH 60/61] libCom/osi: Clean up compiler warnings on vxWorks --- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h | 5 +++++ src/libCom/osi/os/vxWorks/osdSock.h | 16 +++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 2cf981f14..5454e70ba 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -15,6 +15,11 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h +/* This is needed for vxWorks 6.8 to prevent an obnoxious compiler warning */ +#ifndef _VSB_CONFIG_FILE +# define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h> +#endif + #include "vxWorks.h" /* obtain the version of vxWorks */ #include "epicsAssert.h" diff --git a/src/libCom/osi/os/vxWorks/osdSock.h b/src/libCom/osi/os/vxWorks/osdSock.h index 3ebc5799a..362248525 100644 --- a/src/libCom/osi/os/vxWorks/osdSock.h +++ b/src/libCom/osi/os/vxWorks/osdSock.h @@ -3,8 +3,7 @@ * 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. \*************************************************************************/ /* @@ -14,12 +13,10 @@ #ifndef osdSockH #define osdSockH -#ifdef __cplusplus -extern "C" { -#endif - /* This is needed for vxWorks 6.8 to prevent an obnoxious compiler warning */ -#define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h> +#ifndef _VSB_CONFIG_FILE +# define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h> +#endif #include @@ -36,6 +33,11 @@ extern "C" { #include #include #include + +#ifdef __cplusplus +extern "C" { +#endif + /*This following is not defined in any vxWorks header files*/ int sysClkRateGet(void); From 303bc702b2220440372f4b10f8b629df87aa24d8 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 7 Sep 2011 12:16:50 -0500 Subject: [PATCH 61/61] documentation/README: We now require vxWorks 5.5 or later --- documentation/README.html | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/documentation/README.html b/documentation/README.html index e48e91fd3..862d488ec 100644 --- a/documentation/README.html +++ b/documentation/README.html @@ -88,15 +88,18 @@ as processes on the host platform.

vxWorks
- You must have vxWorks installed if any of your target systems are - vxWorks systems. This provides the cross-compiler and header files - needed to build for these target systems. The absolute path to and version - number of the vxWorks installation is normally specified in the - base/configure/os/CONFIG_SITE.Common.vxWorksCommon file. Consult the EPICS web - pages about vxWorks - 5.x and vxWorks - 6.x and the vxWorks documentation for information about configuring your - vxWorks operating system for use with EPICS.

+ You must have vxWorks 5.5.x or 6.x installed if any of your target systems are + vxWorks systems; the C++ compiler for vxWorks 5.4 is now too old to support. + The vxWorks installation provides the cross-compiler and header files needed to + build for these targets. The absolute path to and the version number of the + vxWorks installation must be set in the + base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its + target-specific overrides.

+ +

Consult the vxWorks + 5.x or vxWorks + 6.x EPICS web pages about and the vxWorks documentation for information + about configuring your vxWorks operating system for use with EPICS.

RTEMS
For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or later.