Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019 
<== Date ==> <== Thread ==>

Subject: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base
From: Jeff Hill <johill@lanl.gov>
To: mp+70642@code.launchpad.net
Date: Sat, 06 Aug 2011 00:16:49 -0000
Jeff Hill has proposed merging lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base.

Requested reviews:
  EPICS Core Developers (epics-core)

For more details, see:
https://code.launchpad.net/~epics-core/epics-base/epicsR3.15-atomics/+merge/70642

This is my atomic set/get/incr/decr/test-and-set library which I have reworked quite a bit in the last week. I need to start merging other things for which this is a prerequisite.

The basic strategy is to look for a compiler intrinsic first, then an os specific primitive, and finally to fall back on a global mutex.

At a minimum Andrew, Janet, and Michael should have a look at this.

In particular I made changes in the build system so that we can install compiler, in addition to os  specific header files. That makes it very clean to check with the compiler first to see if it can implement these operations with its intrinsics. We don't end up with endless permutations of compiler specific ifdefs in the os dependent headers. I also made 586 (pentium circa 1995) the minimum architecture by default for mingw and linux so that we can have an efficient implementation.

I have tested this on windows/msvc, windows/gcc, and linux/gcc (see epicsAtomicTest and epicsAtomicPerform in the libCom test directory). I am having troubles building for solaris here due to python issues and also it maybe doesn't help that much because we don't have 5.10 and I wouldn't be able to test the os primitives (only the global lock version). The vxWorks code has been built successfully for old and recent vxWorks, but I haven't run the tests yet. I suspect that RTEMS may just work because the same gcc compiler intrinsics will be used as linux.

all comments appreciated

thanks for your consideration

-- 
https://code.launchpad.net/~epics-core/epics-base/epicsR3.15-atomics/+merge/70642
Your team EPICS Core Developers is requested to review the proposed merge of lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base.
=== modified file 'configure/CONFIG.gnuCommon'
--- configure/CONFIG.gnuCommon	2009-11-25 17:15:47 +0000
+++ configure/CONFIG.gnuCommon	2011-08-06 00:16:47 +0000
@@ -12,6 +12,8 @@
 
 GNU = YES
 
+CMPLR_CLASS = gcc
+
 GNU_BIN = $(GNU_DIR)/bin
 GNU_LIB = $(GNU_DIR)/lib
 

=== modified file 'configure/CONFIG_COMMON'
--- configure/CONFIG_COMMON	2011-06-03 20:28:34 +0000
+++ configure/CONFIG_COMMON	2011-08-06 00:16:47 +0000
@@ -133,11 +133,14 @@
 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,25 +382,36 @@
 #
 # 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
 #
 OS_INSTALL_INC = $(addprefix $(INSTALL_INCLUDE)/os/$(OS_CLASS)/, $(INSTALL_INC_ggg) )

=== modified file 'configure/RULES_BUILD'
--- configure/RULES_BUILD	2011-02-18 22:16:56 +0000
+++ configure/RULES_BUILD	2011-08-06 00:16:47 +0000
@@ -417,6 +417,10 @@
 $(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 $@"

=== modified file 'configure/os/CONFIG.linux-x86.linux-x86'
--- configure/os/CONFIG.linux-x86.linux-x86	2010-10-05 19:27:37 +0000
+++ configure/os/CONFIG.linux-x86.linux-x86	2011-08-06 00:16:47 +0000
@@ -16,3 +16,8 @@
 
 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

=== modified file 'configure/os/CONFIG.solarisCommon.solarisCommon'
--- configure/os/CONFIG.solarisCommon.solarisCommon	2010-10-05 19:27:37 +0000
+++ configure/os/CONFIG.solarisCommon.solarisCommon	2011-08-06 00:16:47 +0000
@@ -7,6 +7,8 @@
 # Sites may override these definitions in CONFIG_SITE.solaris-sparc.solaris-sparc
 #-------------------------------------------------------
 
+CMPLR_CLASS = solStudio
+
 SPARCWORKS = /opt/SUNWspro
 GNU = NO
 

=== modified file 'configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin'
--- configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin	2010-10-05 19:27:37 +0000
+++ configure/os/CONFIG.win32-x86-cygwin.win32-x86-cygwin	2011-08-06 00:16:47 +0000
@@ -23,6 +23,11 @@
 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 =
 

=== modified file 'configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw'
--- configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw	2010-11-08 14:16:12 +0000
+++ configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw	2011-08-06 00:16:47 +0000
@@ -18,6 +18,11 @@
 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)

=== modified file 'configure/os/CONFIG.win32-x86.win32-x86'
--- configure/os/CONFIG.win32-x86.win32-x86	2011-02-16 16:57:20 +0000
+++ configure/os/CONFIG.win32-x86.win32-x86	2011-08-06 00:16:47 +0000
@@ -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 @@
 # /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

=== modified file 'src/libCom/Makefile'
--- src/libCom/Makefile	2010-10-12 16:27:17 +0000
+++ src/libCom/Makefile	2011-08-06 00:16:47 +0000
@@ -184,6 +184,10 @@
 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 += 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 += epicsStdio.c
 SRCS += osdStdio.c
 
+
 osdEnv_CFLAGS_WIN32= -U__STDC__
 
 SRCS += osdThread.c

=== added directory 'src/libCom/osi/compiler'
=== added directory 'src/libCom/osi/compiler/clang'
=== added file 'src/libCom/osi/compiler/clang/epicsAtomicCD.h'
--- src/libCom/osi/compiler/clang/epicsAtomicCD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/compiler/clang/epicsAtomicCD.h	2011-08-06 00:16:47 +0000
@@ -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 epicsAtomicCD_h
+#define epicsAtomicCD_h
+
+#if defined ( __cplusplus )
+#   define OSD_ATOMIC_INLINE inline
+#else
+#   define OSD_ATOMIC_INLINE __inline__
+#endif
+
+#include "epicsAtomicOSD.h"
+
+#endif /* epicsAtomicCD_h */

=== added directory 'src/libCom/osi/compiler/default'
=== added file 'src/libCom/osi/compiler/default/epicsAtomicCD.h'
--- src/libCom/osi/compiler/default/epicsAtomicCD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/compiler/default/epicsAtomicCD.h	2011-08-06 00:16:47 +0000
@@ -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 epicsAtomicCD_h
+#define epicsAtomicCD_h
+
+#if __STDC_VERSION__ >= 199901L || defined ( __cplusplus )
+#   define OSD_ATOMIC_INLINE inline
+#endif
+
+#include "epicsAtomicOSD.h"
+
+#endif /* epicsAtomicCD_h */

=== added directory 'src/libCom/osi/compiler/gcc'
=== added file 'src/libCom/osi/compiler/gcc/epicsAtomicCD.h'
--- src/libCom/osi/compiler/gcc/epicsAtomicCD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/compiler/gcc/epicsAtomicCD.h	2011-08-06 00:16:47 +0000
@@ -0,0 +1,101 @@
+
+/*************************************************************************\
+* 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 epicsAtomicCD_h
+#define epicsAtomicCD_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__ )
+        
+#define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \
+    defined ( __i386 ) && ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401
+
+#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
+
+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 "epicsAtomicOSD.h"
+
+#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL */
+
+#endif /* epicsAtomicCD_h */

=== added directory 'src/libCom/osi/compiler/msvc'
=== added file 'src/libCom/osi/compiler/msvc/epicsAtomicCD.h'
--- src/libCom/osi/compiler/msvc/epicsAtomicCD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/compiler/msvc/epicsAtomicCD.h	2011-08-06 00:16:47 +0000
@@ -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 epicsAtomicCD_h
+#define epicsAtomicCD_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 <intrin.h>
+
+#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 "epicsAtomicOSD.h"
+#endif
+
+#endif /* ifdef _MSC_EXTENSIONS */
+
+#endif /* epicsAtomicCD_h */

=== added directory 'src/libCom/osi/compiler/solStudio'
=== added file 'src/libCom/osi/compiler/solStudio/epicsAtomicCD.h'
--- src/libCom/osi/compiler/solStudio/epicsAtomicCD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/compiler/solStudio/epicsAtomicCD.h	2011-08-06 00:16:47 +0000
@@ -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 epicsAtomicCD_h
+#define epicsAtomicCD_h
+
+#if defined ( __cplusplus )
+#   define OSD_ATOMIC_INLINE inline
+#else
+#   define OSD_ATOMIC_INLINE __inline
+#endif
+
+#include "epicsAtomicOSD.h"
+
+#endif /* epicsAtomicCD_h */

=== added file 'src/libCom/osi/epicsAtomic.h'
--- src/libCom/osi/epicsAtomic.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/epicsAtomic.h	2011-08-06 00:16:47 +0000
@@ -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 <stdlib.h> /* 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 */

=== added file 'src/libCom/osi/epicsAtomicLocked.cpp'
--- src/libCom/osi/epicsAtomicLocked.cpp	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/epicsAtomicLocked.cpp	2011-08-06 00:16:47 +0000
@@ -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" 
+
+
+
+

=== added file 'src/libCom/osi/epicsAtomicLocked.h'
--- src/libCom/osi/epicsAtomicLocked.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/epicsAtomicLocked.h	2011-08-06 00:16:47 +0000
@@ -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 */
+
+

=== added file 'src/libCom/osi/epicsAtomicOSD.cpp'
--- src/libCom/osi/epicsAtomicOSD.cpp	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/epicsAtomicOSD.cpp	2011-08-06 00:16:47 +0000
@@ -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
+ 

=== added file 'src/libCom/osi/os/WIN32/epicsAtomicOSD.h'
--- src/libCom/osi/os/WIN32/epicsAtomicOSD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/WIN32/epicsAtomicOSD.h	2011-08-06 00:16:47 +0000
@@ -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 epicsAtomicOSD_h
+#define epicsAtomicOSD_h
+
+#if defined ( OSD_ATOMIC_INLINE )
+
+#include <limits.h>
+
+#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */
+#include <stdint.h>
+
+#include "epicsAssert.h"
+
+#define STRICT
+#define VC_EXTRALEAN
+#include <windows.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;
+}
+
+/* 
+ * 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 epicsAtomicOSD_h */

=== added file 'src/libCom/osi/os/default/epicsAtomicOSD.h'
--- src/libCom/osi/os/default/epicsAtomicOSD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/default/epicsAtomicOSD.h	2011-08-06 00:16:47 +0000
@@ -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 epicsAtomicOSD_h
+#define epicsAtomicOSD_h
+
+#include "epicsAtomicLocked.h"
+
+#endif /* epicsAtomicOSD_h */

=== added file 'src/libCom/osi/os/solaris/epicsAtomicOSD.h'
--- src/libCom/osi/os/solaris/epicsAtomicOSD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/solaris/epicsAtomicOSD.h	2011-08-06 00:16:47 +0000
@@ -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 epicsAtomicOSD_h
+#define epicsAtomicOSD_h
+
+#if defined ( OSD_ATOMIC_INLINE )
+
+/* 
+ * atomic.h exists only in Solaris 10 or higher
+ */
+#if defined ( __SunOS_5_10 )
+
+#include <limits.h>
+#include <atomic.h>
+
+#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */
+#include <stdint.h>
+
+#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 /* epicsAtomicOSD_h */

=== added file 'src/libCom/osi/os/vxWorks/epicsAtomicOSD.h'
--- src/libCom/osi/os/vxWorks/epicsAtomicOSD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/vxWorks/epicsAtomicOSD.h	2011-08-06 00:16:47 +0000
@@ -0,0 +1,215 @@
+/*************************************************************************\
+* 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 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
+ * to implement this functionality correctly on SMP systems
+ */
+#if _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606
+
+#include <limits.h>
+#include <vxAtomicLib.h>
+     
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * 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 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 ULONG_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 ( pTarg, 0, 1 ) != 0;
+}
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+#else /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
+
+#include "vxLib.h"
+#include "intLib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
+{
+#   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 )
+{
+#   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 )
+{
+    /* 
+     * 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 ) );
+    return vxTas ( pTarget );
+}
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+#endif /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
+
+#endif /* if defined ( OSD_ATOMIC_INLINE ) */
+
+#endif /* epicsAtomicOSD_h */

=== modified file 'src/libCom/test/Makefile'
--- src/libCom/test/Makefile	2010-09-30 19:36:30 +0000
+++ src/libCom/test/Makefile	2011-08-06 00:16:47 +0000
@@ -107,6 +107,11 @@
 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_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

=== added file 'src/libCom/test/epicsAtomicPerform.cpp'
--- src/libCom/test/epicsAtomicPerform.cpp	1970-01-01 00:00:00 +0000
+++ src/libCom/test/epicsAtomicPerform.cpp	2011-08-06 00:16:47 +0000
@@ -0,0 +1,499 @@
+
+#include <cstdlib>
+#include <cassert>
+
+#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(epicsAtomicPerform)
+{
+    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();
+}

=== added file 'src/libCom/test/epicsAtomicTest.c'
--- src/libCom/test/epicsAtomicTest.c	1970-01-01 00:00:00 +0000
+++ src/libCom/test/epicsAtomicTest.c	2011-08-06 00:16:47 +0000
@@ -0,0 +1,118 @@
+
+#include <stdlib.h>
+#include <assert.h>
+
+#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(epicsAtomicTest)
+{
+    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 );
+        testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N,
+                    "set/get %u", testData.m_testValue );
+        epicsAtomicSetSizeT ( & testData.m_testIterations, 0u );
+        testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 0u,
+                    "set/get %u", testData.m_testIterations );
+        for ( i = 0u; i < N; i++ ) {
+            epicsThreadCreate ( "incr",
+                        50, stackSize, incr, & testData );
+            epicsThreadCreate ( "decr",
+                        50, stackSize, decr, & testData );
+        }
+        while ( testData.m_testIterations < 2 * N ) {
+            epicsThreadSleep ( 0.01 );
+        }
+        testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N,
+                    "incr/decr iterations %u", 
+                    testData.m_testIterations );
+        testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, 
+                    "incr/decr final value %u", 
+                    testData.m_testValue );
+    }
+
+    {
+        static const size_t N = 10;
+        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();
+}
+


Replies:
[Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base mdavidsaver
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Andrew Johnson
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill

Navigate by Date:
Prev: Mini-Codeathon at PSI Andrew Johnson
Next: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019 
Navigate by Thread:
Prev: Mini-Codeathon at PSI Andrew Johnson
Next: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Jeff Hill
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·