From ee2e367dad2c449ab91b7e2660b27b256ca6cd15 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 08:57:15 -0600 Subject: [PATCH 01/22] 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 100c79b88b14248daf427bac3d64d302e61be1bd Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 09:13:38 -0600 Subject: [PATCH 02/22] 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 31f5ae048fb526df83f091d05850a9c5799911c9 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 09:51:05 -0600 Subject: [PATCH 03/22] 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 a05a83629571e80540ac2346bc5d4605e04e9eaf Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 10:50:25 -0600 Subject: [PATCH 04/22] 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 d6cfa286b24713cd2aed45a83b4e6572fe543dc7 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 11:14:37 -0600 Subject: [PATCH 05/22] 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 deb74a10b7714d40e5a957fe22ef345d6973321c Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 16:23:50 -0600 Subject: [PATCH 06/22] 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 89e47e5fae482ed3ddd47fd66d840930865a5f27 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 17:11:29 -0600 Subject: [PATCH 07/22] 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 a3d9bf1e3f85793e08d802e6168a61417a608ea8 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 17:12:33 -0600 Subject: [PATCH 08/22] 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 921df1dd5cd266448f0f7bfb575a6c865a26d900 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 5 Aug 2011 17:32:06 -0600 Subject: [PATCH 09/22] 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 eefc3b34e04706a4ed0985871a9eec57e5ae98f2 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 17:33:19 -0600 Subject: [PATCH 10/22] 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 e8bcfbe2c1ce872bd4c060487f931f0fae5ef8a0 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 17:54:43 -0600 Subject: [PATCH 11/22] 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 96723b66d7e7378659cb2d7319700f7185a782bd Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 18:31:42 -0600 Subject: [PATCH 12/22] 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 04c30aee0ebf840b6ce26b73e6677af479381e9b Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 8 Aug 2011 18:38:39 -0600 Subject: [PATCH 13/22] 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 ca78732dac297a14f401a29812ec0828f35ca0a4 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 9 Aug 2011 12:26:40 -0600 Subject: [PATCH 14/22] 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 bd2bccf98272dc816571add7b6c72204638676d4 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Wed, 10 Aug 2011 13:15:51 -0600 Subject: [PATCH 15/22] 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 049e070b3a9d5d8fab772c5686d5368416bf426c Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Thu, 11 Aug 2011 09:49:09 -0600 Subject: [PATCH 16/22] 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 a50482a0c9d46cab83df9243359a506f1d579cf9 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 12 Aug 2011 10:06:09 -0600 Subject: [PATCH 17/22] 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 b9900b86825e745ca0ba49ed995ce24b58142d52 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 15 Aug 2011 17:00:01 -0600 Subject: [PATCH 18/22] 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 baaaa3a3134fc59f8ebc725cc76a7ad0438ef0e9 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Mon, 15 Aug 2011 17:59:43 -0600 Subject: [PATCH 19/22] 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 159ca986a37061cd3d564de4acc6cfdbb29061b1 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 16 Aug 2011 18:32:41 -0600 Subject: [PATCH 20/22] 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 9b8ee4186031c726db8c26ed9d723fc7d6af69ba Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Wed, 17 Aug 2011 09:05:05 -0600 Subject: [PATCH 21/22] 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 4d8045ab5abff06821ef3f2bbb8c5709617a566d Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 19 Aug 2011 13:48:03 -0600 Subject: [PATCH 22/22] 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" {