EPICS Controls 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  2020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Merge] lp:~epics-core/epics-base/rebased-atomics into lp:epics-base
From: Andrew Johnson <[email protected]>
To: [email protected]
Date: Fri, 02 Sep 2011 23:09:27 -0000
Andrew Johnson has proposed merging lp:~epics-core/epics-base/rebased-atomics into lp:epics-base.

Requested reviews:
  EPICS Core Developers (epics-core)

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

This is Jeff Hill's atomics branch, rebased onto the 3.15 trunk.
-- 
https://code.launchpad.net/~epics-core/epics-base/rebased-atomics/+merge/73915
Your team EPICS Core Developers is requested to review the proposed merge of lp:~epics-core/epics-base/rebased-atomics into lp:epics-base.
=== modified file 'configure/RULES_BUILD'
--- configure/RULES_BUILD	2011-09-02 21:24:09 +0000
+++ configure/RULES_BUILD	2011-09-02 23:09:24 +0000
@@ -410,7 +410,7 @@
 $(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)

=== modified file 'configure/os/CONFIG.win32-x86.win32-x86'
--- configure/os/CONFIG.win32-x86.win32-x86	2011-09-01 16:42:37 +0000
+++ configure/os/CONFIG.win32-x86.win32-x86	2011-09-02 23:09:24 +0000
@@ -124,7 +124,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/osi/Makefile'
--- src/libCom/osi/Makefile	2011-09-01 16:42:37 +0000
+++ src/libCom/osi/Makefile	2011-09-02 23:09:24 +0000
@@ -44,6 +44,11 @@
 INC += osiWireFormat.h
 INC += osdWireFormat.h
 INC += osdWireConfig.h
+INC += epicsAtomic.h
+INC += epicsAtomicDefault.h
+INC += epicsAtomicLocked.h
+INC += epicsAtomicOSD.h
+INC += epicsAtomicCD.h
 INC += epicsEndian.h
 INC += epicsReadline.h
 INC += epicsMessageQueue.h
@@ -62,6 +67,8 @@
 Com_SRCS += epicsTime.cpp
 Com_SRCS += epicsMessageQueue.cpp
 Com_SRCS += epicsMath.cpp
+Com_SRCS += epicsAtomicLocked.cpp
+Com_SRCS += epicsAtomicOSD.cpp
 
 Com_SRCS += epicsGeneralTime.c
 
@@ -125,6 +132,8 @@
 #This forces the vxWorks compatibility stuff to be loaded
 OBJS_vxWorks = vxComLibrary
 
+INC_WIN32 += epicsAtomicMS.h
+
 Com_SRCS_WIN32 += epicsGetopt.c 
 Com_SRCS_WIN32 += setThreadName.cpp
 #Com_SRCS_WIN32 += dllmain.cpp

=== 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-09-02 23:09:24 +0000
@@ -0,0 +1,31 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#ifndef epicsAtomicCD_h
+#define epicsAtomicCD_h
+
+#if defined ( __cplusplus )
+#   define EPICS_ATOMIC_INLINE inline
+#else
+#   define EPICS_ATOMIC_INLINE __inline__
+#endif
+
+/* 
+ * we have an inline keyword so we can proceed
+ * with an os specific inline instantiation
+ */
+#include "epicsAtomicOSD.h"
+
+#endif /* epicsAtomicCD_h */

=== 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-09-02 23:09:24 +0000
@@ -0,0 +1,30 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#ifndef epicsAtomicCD_h
+#define epicsAtomicCD_h
+
+#if __STDC_VERSION__ >= 199901L || defined ( __cplusplus )
+#   define EPICS_ATOMIC_INLINE inline
+    /*
+     * We have already defined the public interface in epicsAtomic.h
+     * so there is nothing more to implement if there isnt an inline 
+     * keyword available. Otherwise, if we have an inline keyword
+     * we will proceed with an os specific inline implementation.
+     */
+#   include "epicsAtomicOSD.h"
+#endif
+
+#endif /* epicsAtomicCD_h */

=== 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-09-02 23:09:24 +0000
@@ -0,0 +1,172 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#ifndef epicsAtomicCD_h
+#define epicsAtomicCD_h
+
+#ifndef __GNUC__
+#   error this header is only for use with the gnu compiler
+#endif
+
+#define EPICS_ATOMIC_INLINE __inline__
+
+#define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B)
+#define GCC_ATOMIC_CONCATR( A, B ) ( A ## B )
+
+#define GCC_ATOMIC_INTRINSICS_AVAIL_INT_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_MIN_X86 \
+    ( 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 && \
+    GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER )
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 
+ * We are optimistic that __sync_synchronize is implemented
+ * in all version four gcc invarient of target. The gnu doc 
+ * seems to say that when not supported by architecture a call
+ * to an external function is generated but in practice
+ * this isnt the case for some of the atomic intrinsics, and 
+ * so there is an undefined symbol. So far we have not seen 
+ * that with __sync_synchronize, but we can only guess based
+ * on experimental evidence.
+ *
+ * For example we know that when generating object code for
+ * 386 most of the atomic instrinsics are not present and
+ * we see undefined symbols with mingw, but we dont have
+ * troubles with __sync_synchronize.
+ */
+#if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER
+
+#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
+#define EPICS_ATOMIC_READ_MEMORY_BARRIER
+EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()
+{
+    __sync_synchronize ();
+}
+#endif
+
+#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
+#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
+EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()
+{
+    __sync_synchronize ();
+}
+#endif
+
+#endif /* if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER */
+
+#if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \
+    || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER 
+
+#define EPICS_ATOMIC_INCR_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
+{
+    return __sync_add_and_fetch ( pTarget, 1 );
+}
+
+#define EPICS_ATOMIC_DECR_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
+{
+    return __sync_sub_and_fetch ( pTarget, 1 );
+}
+
+#define EPICS_ATOMIC_ADD_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
+{
+    return __sync_add_and_fetch ( pTarget, delta ); 
+}
+
+#define EPICS_ATOMIC_CAS_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, 
+                                        int oldVal, int newVal )
+{
+    return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
+}
+
+#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T */
+
+#if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
+    || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER 
+
+#define EPICS_ATOMIC_INCR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
+{
+    return __sync_add_and_fetch ( pTarget, 1u );
+}
+
+#define EPICS_ATOMIC_DECR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
+{
+    return __sync_sub_and_fetch ( pTarget, 1u );
+}
+
+#define EPICS_ATOMIC_ADD_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
+{
+    return __sync_add_and_fetch ( pTarget, delta ); 
+}
+
+#define EPICS_ATOMIC_SUB_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
+{
+    return __sync_sub_and_fetch ( pTarget, delta ); 
+}
+
+#define EPICS_ATOMIC_CAS_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, 
+                                        size_t oldVal, size_t newVal )
+{
+    return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
+}
+
+#define EPICS_ATOMIC_CAS_PTRT
+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( 
+                            EpicsAtomicPtrT * pTarget, 
+                            EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
+{
+    return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
+}
+
+#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T */
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+/*
+ * if currently unavailable as gcc intrinsics we
+ * will try for an os specific inline solution
+ */
+#include "epicsAtomicOSD.h"
+
+#endif /* epicsAtomicCD_h */

=== 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-09-02 23:09:24 +0000
@@ -0,0 +1,124 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#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
+
+#include <intrin.h>
+
+#if _MSC_VER >= 1200
+#   define EPICS_ATOMIC_INLINE __forceinline
+#else
+#   define EPICS_ATOMIC_INLINE __inline
+#endif
+
+#if defined ( _M_IX86 )
+#   pragma warning( push )
+#   pragma warning( disable : 4793 )
+    EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier ()
+    {
+        long fence;
+        __asm { xchg fence, eax }
+    }
+#   pragma warning( pop )
+#elif defined ( _M_X64 )
+#   define MS_ATOMIC_64
+#   pragma intrinsic ( __faststorefence )
+    EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier () 
+    { 
+        __faststorefence ();
+    }
+#elif defined ( _M_IA64 )
+#   define MS_ATOMIC_64
+#   pragma intrinsic ( __mf )
+    EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier () 
+    { 
+        __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
+ * creates issues when later, in a windows os specific header, we include
+ * windows.h. Therefore, we except some code duplication between the msvc 
+ * csAtomic.h and win32 osdAtomic.h to avoid problems, and to keep the 
+ * os specific windows.h header file out of the msvc cdAtomic.h
+ */
+#define MS_LONG long
+#define MS_InterlockedExchange _InterlockedExchange
+#define MS_InterlockedCompareExchange _InterlockedCompareExchange
+#define MS_InterlockedIncrement _InterlockedIncrement 
+#define MS_InterlockedDecrement _InterlockedDecrement 
+#define MS_InterlockedExchange _InterlockedExchange
+#define MS_InterlockedExchangeAdd _InterlockedExchangeAdd
+#if defined ( MS_ATOMIC_64 ) 
+#   define MS_LONGLONG long long
+#   define MS_InterlockedIncrement64 _InterlockedIncrement64
+#   define MS_InterlockedDecrement64 _InterlockedDecrement64 
+#   define MS_InterlockedExchange64 _InterlockedExchange64 
+#   define MS_InterlockedExchangeAdd64 _InterlockedExchangeAdd64 
+#   define MS_InterlockedCompareExchange64 _InterlockedCompareExchange64
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define EPICS_ATOMIC_READ_MEMORY_BARRIER
+EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()
+{
+    epicsAtomicMemoryBarrier ();
+}
+
+#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
+EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()
+{
+    epicsAtomicMemoryBarrier ();
+}
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+#include "epicsAtomicMS.h"
+#include "epicsAtomicDefault.h"
+
+#else /* ifdef _MSC_EXTENSIONS */
+
+#if defined ( __cplusplus )
+#   define EPICS_ATOMIC_INLINE inline
+#endif
+
+/* 
+ * if unavailable as an intrinsic we will try
+ * for os specific inline solution
+ */
+#include "epicsAtomicOSD.h"
+
+#endif /* ifdef _MSC_EXTENSIONS */
+
+#endif /* epicsAtomicCD_h */
+

=== 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-09-02 23:09:24 +0000
@@ -0,0 +1,31 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#ifndef epicsAtomicCD_h
+#define epicsAtomicCD_h
+
+#if defined ( __cplusplus )
+#   define EPICS_ATOMIC_INLINE inline
+#else
+#   define EPICS_ATOMIC_INLINE __inline
+#endif
+
+/* 
+ * we have an inline keyword so we can proceed
+ * with an os specific inline instantiation
+ */
+#include "epicsAtomicOSD.h"
+
+#endif /* epicsAtomicCD_h */

=== 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-09-02 23:09:24 +0000
@@ -0,0 +1,236 @@
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#ifndef epicsAtomic_h
+#define epicsAtomic_h
+
+#include <stdlib.h> /* define size_t */
+
+#include "shareLib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void * EpicsAtomicPtrT;
+
+/* load target into cache */
+epicsShareFunc void epicsAtomicReadMemoryBarrier ();
+
+/* push cache version of target into target */
+epicsShareFunc void epicsAtomicWriteMemoryBarrier ();
+
+/*
+ * lock out other smp processors from accessing the target,
+ * load target into cache, add one to target, flush cache 
+ * to target, allow other smp processors to access the target,
+ * return new value of target as modified by this operation
+ */
+epicsShareFunc size_t epicsAtomicIncrSizeT ( size_t * pTarget );
+epicsShareFunc int epicsAtomicIncrIntT ( int * pTarget );
+
+/*
+ * lock out other smp processors from accessing the target,
+ * load target into cache, subtract one from target, flush cache 
+ * to target, allow out other smp processors to access the target,
+ * return new value of target as modified by this operation
+ */
+epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget );
+epicsShareFunc int epicsAtomicDecrIntT ( int * pTarget );
+
+/*
+ * lock out other smp processors from accessing the target,
+ * load target into cache, add/sub delta to/from target, flush cache 
+ * to target, allow other smp processors to access the target,
+ * return new value of target as modified by this operation
+ */
+epicsShareFunc size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta );
+epicsShareFunc size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta );
+epicsShareFunc int epicsAtomicAddIntT ( int * pTarget, int delta );
+
+/*
+ * set cache version of target, flush cache to target 
+ */
+epicsShareFunc void epicsAtomicSetSizeT  ( size_t * pTarget, size_t newValue ); 
+epicsShareFunc void epicsAtomicSetIntT ( int * pTarget, int newValue );
+epicsShareFunc void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue );
+
+/*
+ * fetch target into cache, return new value of target
+ */
+epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget );
+epicsShareFunc int epicsAtomicGetIntT ( const int * pTarget );
+epicsShareFunc EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget );
+
+/*
+ * lock out other smp processors from accessing the target,
+ * load target into cache, if target is equal to oldVal set target 
+ * to newVal, flush cache to target, allow other smp processors 
+ * to access the target, return the original value stored in the
+ * target
+ */
+epicsShareFunc size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, 
+                                            size_t oldVal, size_t newVal );
+epicsShareFunc int epicsAtomicCmpAndSwapIntT ( int * pTarget, 
+                                            int oldVal, int newVal );
+epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( 
+                                            EpicsAtomicPtrT * pTarget, 
+                                            EpicsAtomicPtrT oldVal, 
+                                            EpicsAtomicPtrT newVal );
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+/*
+ * options for inline compiler instrinsic or os specific 
+ * implementations of the above function prototypes
+ *
+ * for some of the compilers we must define the
+ * inline functions before they get used in the c++ 
+ * inine functions below
+ */
+#include "epicsAtomicCD.h"
+
+#ifdef __cplusplus
+
+namespace epics {
+namespace atomic {
+
+/* 
+ * overloaded c++ interface 
+ */
+epicsShareFunc size_t increment ( size_t & v );
+epicsShareFunc int increment ( int & v );
+epicsShareFunc size_t decrement ( size_t & v );
+epicsShareFunc int decrement ( int & v );
+epicsShareFunc size_t add ( size_t & v, size_t delta );
+epicsShareFunc int add ( int & v, int delta );
+epicsShareFunc size_t subtract ( size_t & v, size_t delta );
+epicsShareFunc int subtract ( int & v, int delta );
+epicsShareFunc void set ( size_t & v , size_t newValue );
+epicsShareFunc void set ( int & v, int newValue );
+epicsShareFunc void set ( EpicsAtomicPtrT & v, 
+                                     EpicsAtomicPtrT newValue );
+epicsShareFunc size_t get ( const size_t & v );
+epicsShareFunc int get ( const int & v );
+epicsShareFunc EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v );
+epicsShareFunc size_t compareAndSwap ( size_t & v, size_t oldVal, 
+                                                       size_t newVal );
+epicsShareFunc int compareAndSwap ( int & v, int oldVal, int newVal );
+epicsShareFunc EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v, 
+                                                EpicsAtomicPtrT oldVal, 
+                                                EpicsAtomicPtrT newVal );
+
+/************* incr ***************/
+inline size_t increment ( size_t & v )
+{
+    return epicsAtomicIncrSizeT ( & v );
+}
+
+inline int increment ( int & v )
+{
+    return epicsAtomicIncrIntT ( & v );
+}
+
+/************* decr ***************/
+inline size_t decrement ( size_t & v )
+{
+    return epicsAtomicDecrSizeT ( & v );
+}
+
+inline int decrement ( int & v )
+{
+    return epicsAtomicDecrIntT ( & v );
+}
+
+/************* add ***************/
+inline size_t add ( size_t & v, size_t delta )
+{
+    return epicsAtomicAddSizeT ( & v, delta );
+}
+
+inline int add ( int & v, int delta )
+{
+    return epicsAtomicAddIntT ( & v, delta );
+}
+
+/************* sub ***************/
+inline size_t subtract ( size_t & v, size_t delta )
+{
+    return epicsAtomicSubSizeT ( & v, delta );
+}
+
+inline int subtract ( int & v, int delta )
+{
+    return epicsAtomicAddIntT ( & v, -delta );
+}
+
+/************* set ***************/
+inline void set ( size_t & v , size_t newValue ) 
+{ 
+    epicsAtomicSetSizeT  ( & v, newValue ); 
+}
+
+inline void set ( int & v, int newValue )
+{
+    epicsAtomicSetIntT ( & v, newValue );
+}
+
+inline void set ( EpicsAtomicPtrT & v, EpicsAtomicPtrT newValue )
+{
+    epicsAtomicSetPtrT ( & v, newValue );
+}
+
+/************* get ***************/
+inline size_t get ( const size_t & v )
+{
+    return epicsAtomicGetSizeT ( & v );
+}
+
+inline int get ( const int & v )
+{
+    return epicsAtomicGetIntT ( & v );
+}
+
+inline EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v )
+{
+    return epicsAtomicGetPtrT ( & v );
+}
+
+/************* cas ***************/
+inline size_t compareAndSwap ( size_t & v, 
+                                           size_t oldVal, size_t newVal )
+{
+    return epicsAtomicCmpAndSwapSizeT ( & v, oldVal, newVal );
+}
+
+inline int compareAndSwap ( int & v, int oldVal, int newVal )
+{
+    return epicsAtomicCmpAndSwapIntT ( & v, oldVal, newVal );
+}
+
+inline EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v, 
+                                            EpicsAtomicPtrT oldVal, 
+                                            EpicsAtomicPtrT newVal )
+{
+    return epicsAtomicCmpAndSwapPtrT ( & v, oldVal, newVal );
+}
+
+} /* end of namespace atomic */
+} /* end of namespace epics */ 
+
+#endif /* ifdef __cplusplus */
+
+#endif /* epicsAtomic_h */

=== added file 'src/libCom/osi/epicsAtomicDefault.h'
--- src/libCom/osi/epicsAtomicDefault.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/epicsAtomicDefault.h	2011-09-02 23:09:24 +0000
@@ -0,0 +1,227 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+ 
+#ifndef epicsAtomicDefault_h
+#define epicsAtomicDefault_h
+
+#ifdef __cpluplus
+extern "C" {
+#endif
+
+/*
+ * struct EpicsAtomicLockKey;
+ * epicsShareFunc void epicsAtomicReadMemoryBarrier ();
+ * epicsShareFunc void epicsAtomicWriteMemoryBarrier ();
+ * epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * );
+ * epicsShareFunc void epicsAtomicUnock ( struct EpicsAtomicLockKey * );
+ */
+
+/*
+ * incr 
+ */
+#ifndef EPICS_ATOMIC_INCR_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
+{
+    EpicsAtomicLockKey key; 
+    epicsAtomicLock ( & key );
+    const int result = ++(*pTarget);
+    epicsAtomicUnlock ( & key );
+    return result;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_INCR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
+{
+    EpicsAtomicLockKey key;
+    epicsAtomicLock ( & key );
+    const size_t result = ++(*pTarget);
+    epicsAtomicUnlock ( & key );
+    return result;
+}
+#endif
+
+/*
+ * decr 
+ */
+#ifndef EPICS_ATOMIC_DECR_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
+{
+    EpicsAtomicLockKey key;
+    epicsAtomicLock ( & key );
+    const int result = --(*pTarget);
+    epicsAtomicUnlock ( & key );
+    return result;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_DECR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
+{
+    EpicsAtomicLockKey key;
+    epicsAtomicLock ( & key );
+    const size_t result = --(*pTarget);
+    epicsAtomicUnlock ( & key );
+    return result;
+}
+#endif
+
+/*
+ * add/sub 
+ */
+#ifndef EPICS_ATOMIC_ADD_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
+{
+    EpicsAtomicLockKey key;
+    epicsAtomicLock ( & key );
+    const int result = *pTarget += delta;
+    epicsAtomicUnlock ( & key );
+    return result;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_ADD_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
+{
+    EpicsAtomicLockKey key;
+    epicsAtomicLock ( & key );
+    const size_t result = *pTarget += delta;
+    epicsAtomicUnlock ( & key );
+    return result;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_SUB_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
+{
+    EpicsAtomicLockKey key;
+    epicsAtomicLock ( & key );
+    const size_t result = *pTarget -= delta;
+    epicsAtomicUnlock ( & key );
+    return result;
+}
+#endif
+
+/*
+ * set
+ */
+#ifndef EPICS_ATOMIC_SET_INTT
+EPICS_ATOMIC_INLINE void epicsAtomicSetIntT ( int * pTarget, int newVal )
+{
+    *pTarget = newVal;
+    epicsAtomicWriteMemoryBarrier ();
+}
+#endif
+
+#ifndef EPICS_ATOMIC_SET_SIZET
+EPICS_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
+{
+    *pTarget = newVal;
+    epicsAtomicWriteMemoryBarrier ();
+}
+#endif
+
+#ifndef EPICS_ATOMIC_SET_PTRT
+EPICS_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, 
+						EpicsAtomicPtrT newVal )
+{
+    *pTarget = newVal;
+    epicsAtomicWriteMemoryBarrier ();
+}
+#endif
+
+/*
+ * get 
+ */
+#ifndef EPICS_ATOMIC_GET_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicGetIntT ( const int * pTarget )
+{
+    epicsAtomicReadMemoryBarrier ();
+    return *pTarget;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_GET_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
+{
+    epicsAtomicReadMemoryBarrier ();
+    return *pTarget;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_GET_PTRT
+EPICS_ATOMIC_INLINE EpicsAtomicPtrT 
+        epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget )
+{
+    epicsAtomicReadMemoryBarrier ();
+    return *pTarget;
+}
+#endif
+
+/*
+ * cmp and swap 
+ */
+#ifndef EPICS_ATOMIC_CAS_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, int oldval, int newval )
+{
+    EpicsAtomicLockKey key; 
+    epicsAtomicLock ( & key );
+    const int cur = *pTarget;
+    if ( cur == oldval ) {
+        *pTarget = newval;
+    }
+    epicsAtomicUnlock ( & key );
+    return cur;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, 
+				size_t oldval, size_t newval )
+{
+    EpicsAtomicLockKey key; 
+    epicsAtomicLock ( & key );
+    const size_t cur = *pTarget;
+    if ( cur == oldval ) {
+        *pTarget = newval;
+    }
+    epicsAtomicUnlock ( & key );
+    return cur;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_PTRT
+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( 
+                            EpicsAtomicPtrT * pTarget, 
+                            EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval )
+{
+    EpicsAtomicLockKey key;
+    epicsAtomicLock ( & key );
+    const EpicsAtomicPtrT cur = *pTarget;
+    if ( cur == oldval ) {
+        *pTarget = newval;
+    }
+    epicsAtomicUnlock ( & key );
+    return cur;
+}
+#endif
+
+#ifdef __cpluplus
+} /* end of extern "C" */
+#endif
+
+#endif /* epicsAtomicDefault_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-09-02 23:09:24 +0000
@@ -0,0 +1,154 @@
+/*************************************************************************\
+* 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
+ *  [email protected]
+ *
+ * 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" 
+

=== 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-09-02 23:09:24 +0000
@@ -0,0 +1,118 @@
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+ 
+//
+// The epicsAtomicXxxxx functions herein are implemented with C++ but directly 
+// callable by C code, and therefore they must not be instantiated inline. 
+// Therefore, this isnt a traditional header file because it has function
+// definitions that are not inline, and must therefore be included by only 
+// one module in the executable - typically this is the epicsAtomicOSD
+// c++ source file. These out-of-line function definitions are placed in a
+// header file so that there is potential code reuse when instantiating for 
+// a specific OS. An alternative option would have been to place these 
+// function definitions in a OS type conditionally compiled source file
+// but this wasnt done because I suspect that selecting the posix version
+// would require a proliferation of "SRCS_XXXX += xxx.cpp" in the libCom 
+// Makefile for every variety of Unix (a maintenance headache when new 
+// varieties of UNIX are configured).
+//
+// Aee also the comments in epicsAtomicGuard header.
+//
+
+#ifndef epicsAtomicLocked_h
+#define epicsAtomicLocked_h
+
+#ifndef __cplusplus
+#   error epicsAtomicLocked.h is intended only for use only by C++ code
+#endif
+
+#include "epicsAtomic.h" // always cross check the function prototypes
+#include "epicsAtomicGuard.h" 
+
+extern "C" {
+
+size_t epicsAtomicIncrSizeT ( size_t * pTarget )
+{
+    AtomicGuard atomicGuard;
+    return ++(*pTarget);
+}
+
+size_t epicsAtomicDecrSizeT ( size_t * pTarget )
+{
+    AtomicGuard atomicGuard;
+    return --(*pTarget);
+}
+
+void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
+{
+    AtomicGuard atomicGuard;
+    *pTarget = newVal;
+}
+
+void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
+{
+    AtomicGuard atomicGuard;
+    *pTarget = newVal;
+}
+
+void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal )
+{
+    AtomicGuard atomicGuard;
+    *pTarget = newVal;
+}
+
+unsigned epicsAtomicGetUIntT ( const unsigned * pTarget )
+{
+    AtomicGuard atomicGuard;
+    return *pTarget;
+}
+
+size_t epicsAtomicGetSizeT ( const size_t * pTarget )
+{
+    AtomicGuard atomicGuard;
+    return *pTarget;
+}
+
+EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget )
+{
+    AtomicGuard atomicGuard;
+    return *pTarget;
+}
+
+unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, 
+                            unsigned oldval, unsigned newval )
+{
+    AtomicGuard atomicGuard;
+    const unsigned cur = *pTarget;
+    if ( cur == oldval ) {
+        *pTarget = newval;
+    }
+    return cur;
+}
+
+EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, 
+                            EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval )
+{
+    AtomicGuard atomicGuard;
+    const EpicsAtomicPtrT cur = *pTarget;
+    if ( cur == oldval ) {
+        *pTarget = newval;
+    }
+    return cur;
+}
+
+} // end of extern "C"
+
+#endif /* epicsAtomicLocked_h */
+

=== added file 'src/libCom/osi/os/WIN32/epicsAtomicMS.h'
--- src/libCom/osi/os/WIN32/epicsAtomicMS.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/WIN32/epicsAtomicMS.h	2011-09-02 23:09:24 +0000
@@ -0,0 +1,222 @@
+
+/*************************************************************************\
+* Copyright (c) 2011 LANS LLC, as Operator of
+*     Los Alamos National Laboratory.
+* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
+*     National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution. 
+\*************************************************************************/
+
+/*
+ *  Author Jeffrey O. Hill
+ *  [email protected]
+ */
+
+#ifndef epicsAtomicMS_h
+#define epicsAtomicMS_h
+
+#include "epicsAssert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef EPICS_ATOMIC_INCR_INTT
+#define EPICS_ATOMIC_INCR_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
+{
+    STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
+    MS_LONG * const pTarg = ( MS_LONG * ) pTarget;
+    return MS_InterlockedIncrement ( pTarg );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_DECR_INTT
+#define EPICS_ATOMIC_DECR_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
+{
+    STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
+    MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
+    return MS_InterlockedDecrement ( pTarg );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_ADD_INTT
+#define EPICS_ATOMIC_ADD_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
+{
+    STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
+    MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
+    /* we dont use InterlockedAdd because only latest windows is supported */
+    return delta + ( int ) MS_InterlockedExchangeAdd ( pTarg, 
+                                            ( MS_LONG ) delta );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_INTT
+#define EPICS_ATOMIC_CAS_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, 
+                                            int oldVal, int newVal )
+{
+    STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
+    MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
+    return (int) MS_InterlockedCompareExchange ( pTarg, 
+                                    (MS_LONG) newVal, (MS_LONG) oldVal );
+}
+#endif
+
+#if ! defined ( MS_ATOMIC_64 )
+
+/*
+ * necessary for next three functions 
+ *
+ * looking at the MS documentation it appears that they will
+ * keep type long the same size as an int on 64 bit builds
+ */
+STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( size_t ) );
+
+#ifndef EPICS_ATOMIC_INCR_SIZET
+#define EPICS_ATOMIC_INCR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
+{
+    MS_LONG * const pTarg = ( MS_LONG * ) pTarget;
+    return MS_InterlockedIncrement ( pTarg );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_DECR_SIZET
+#define EPICS_ATOMIC_DECR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
+{
+    MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
+    return MS_InterlockedDecrement ( pTarg );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_ADD_SIZET
+#define EPICS_ATOMIC_ADD_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, 
+                                                    size_t delta )
+{
+    MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
+    /* we dont use InterlockedAdd because only latest windows is supported */
+    return delta + ( size_t ) MS_InterlockedExchangeAdd ( pTarg, 
+                                                 ( MS_LONG ) delta );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_SUB_SIZET
+#define EPICS_ATOMIC_SUB_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
+{
+    MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
+    MS_LONG ldelta = (MS_LONG) delta;
+    /* we dont use InterlockedAdd because only latest windows is supported */
+    return ( ( size_t ) MS_InterlockedExchangeAdd ( pTarg, -ldelta ) ) - delta;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_SIZET
+#define EPICS_ATOMIC_CAS_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( 
+                                    size_t * pTarget, 
+                                    size_t oldVal, size_t newVal )
+{
+    MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
+    return (size_t) MS_InterlockedCompareExchange ( pTarg, 
+                                    (MS_LONG) newVal, (MS_LONG) oldVal );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_PTRT
+#define EPICS_ATOMIC_CAS_PTRT
+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( 
+                                    EpicsAtomicPtrT * pTarget, 
+                                    EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
+{
+    MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
+    return (EpicsAtomicPtrT) MS_InterlockedCompareExchange ( pTarg, 
+                                    (MS_LONG) newVal, (MS_LONG) oldVal );
+}
+#endif
+
+#else /* ! MS_ATOMIC_64 */
+
+/*
+ * necessary for next three functions 
+ */
+STATIC_ASSERT ( sizeof ( MS_LONGLONG ) == sizeof ( size_t ) );
+
+#ifndef EPICS_ATOMIC_INCR_SIZET
+#define EPICS_ATOMIC_INCR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
+{
+    MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) pTarget;
+    return ( size_t ) MS_InterlockedIncrement64 ( pTarg );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_DECR_SIZET
+#define EPICS_ATOMIC_DECR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
+{
+    MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
+    return ( size_t ) MS_InterlockedDecrement64 ( pTarg );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_ADD_SIZET
+#define EPICS_ATOMIC_ADD_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
+{
+    MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
+    /* we dont use InterlockedAdd64 because only latest windows is supported */
+    return delta + ( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, 
+                                        ( MS_LONGLONG ) delta );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_SUB_SIZET
+#define EPICS_ATOMIC_SUB_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
+{
+    MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
+    MS_LONGLONG ldelta = (MS_LONGLONG) delta;
+    /* we dont use InterlockedAdd64 because only latest windows is supported */
+    return (( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, -ldelta )) - delta;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_SIZET
+#define EPICS_ATOMIC_CAS_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, 
+                                    size_t oldVal, size_t newVal )
+{
+    MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
+    return (size_t) MS_InterlockedCompareExchange64 ( pTarg, 
+                                    (MS_LONGLONG) newVal, 
+                                    (MS_LONGLONG) oldVal );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_PTRT
+#define EPICS_ATOMIC_CAS_PTRT
+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( 
+                            EpicsAtomicPtrT * pTarget, 
+                            EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
+{
+    MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
+    return (EpicsAtomicPtrT) MS_InterlockedCompareExchange64 ( pTarg, 
+                                    (MS_LONGLONG) newVal, (MS_LONGLONG) oldVal );
+}
+#endif
+
+#endif /* ! MS_ATOMIC_64 */
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+#endif /* ifdef epicsAtomicMS_h */
+

=== added file 'src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp'
--- src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp	2011-09-02 23:09:24 +0000
@@ -0,0 +1,22 @@
+
+/*************************************************************************\
+* Copyright (c) 2011 LANS LLC, as Operator of 
+*     Los Alamos National Laboratory.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution. 
+\*************************************************************************/
+
+/*
+ *  Author Jeffrey O. Hill
+ *  [email protected]
+ */
+
+#define epicsExportSharedSymbols
+#include "epicsAtomic.h"
+
+// if the compiler is unable to inline then instantiate out-of-line
+#ifndef EPICS_ATOMIC_INLINE
+#   define EPICS_ATOMIC_INLINE
+#   include "epicsAtomicOSD.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-09-02 23:09:24 +0000
@@ -0,0 +1,47 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#ifndef epicsAtomicOSD_h
+#define epicsAtomicOSD_h
+
+#define VC_EXTRALEAN
+#define STRICT
+#include "windows.h"
+
+#if defined ( _WIN64 )
+#    define MS_ATOMIC_64
+#endif
+
+#define MS_LONG LONG 
+#define MS_InterlockedExchange InterlockedExchange
+#define MS_InterlockedCompareExchange InterlockedCompareExchange
+#define MS_InterlockedIncrement InterlockedIncrement 
+#define MS_InterlockedDecrement InterlockedDecrement 
+#define MS_InterlockedExchange InterlockedExchange
+#define MS_InterlockedExchangeAdd InterlockedExchangeAdd
+#if defined ( MS_ATOMIC_64 )
+#   define MS_LONGLONG LONGLONG 
+#   define MS_InterlockedIncrement64 InterlockedIncrement64
+#   define MS_InterlockedDecrement64 InterlockedDecrement64 
+#   define MS_InterlockedExchange64 InterlockedExchange64 
+#   define MS_InterlockedExchangeAdd64 InterlockedExchangeAdd64 
+#   define MS_InterlockedCompareExchange InterlockedCompareExchange64
+#endif
+
+#include "epicsAtomicMS.h"
+#include "epicsAtomicDefault.h"
+
+#endif /* epicsAtomicOSD_h */
+

=== added file 'src/libCom/osi/os/posix/epicsAtomicOSD.cpp'
--- src/libCom/osi/os/posix/epicsAtomicOSD.cpp	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/posix/epicsAtomicOSD.cpp	2011-09-02 23:09:24 +0000
@@ -0,0 +1,99 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#define epicsExportSharedSymbols
+#include "epicsAssert.h"
+#include "epicsAtomic.h"
+
+// if the compiler is unable to inline then instantiate out-of-line
+#ifndef EPICS_ATOMIC_INLINE
+#   define EPICS_ATOMIC_INLINE
+#   include "epicsAtomicOSD.h"
+#endif
+
+#ifndef EPICS_ATOMIC_LOCK
+
+/*
+ * Slow, but probably correct on all systems.
+ * Useful only if something more efficent isnt 
+ * provided based on knowledge of the compiler 
+ * or OS 
+ *
+ * A statically initialized pthread mutex doesnt 
+ * need to be destroyed 
+ * 
+ * !!!!!
+ * !!!!! WARNING 
+ * !!!!!
+ * !!!!! Do not use this implementation on systems where
+ * !!!!! code runs at interrupt context. If so, then 
+ * !!!!! an implementation must be provided that is based
+ * !!!!! on a compiler intrinsic or an interrpt lock and or
+ * !!!!! a spin lock primitive
+ * !!!!!
+ */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void epicsAtomicLock ( EpicsAtomicLockKey * )
+{
+    unsigned countDown = 1000u;
+    int status;
+    while ( true ) {
+        status = pthread_mutex_lock ( & mutex );
+        if ( status == 0 ) return;
+        assert ( status == EINTR );
+        static const useconds_t retryDelayUSec = 100000;
+        usleep ( retryDelayUSec );
+        countDown--;
+        assert ( countDown );
+    }
+}
+
+void epicsAtomicUnlock ( EpicsAtomicLockKey * )
+{
+    const int status = pthread_mutex_unlock ( & mutex );
+    assert ( status == 0 );
+}
+
+#endif // ifndef EPICS_ATOMIC_LOCK
+
+#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
+// Slow, but probably correct on all systems.
+// Useful only if something more efficent isnt 
+// provided based on knowledge of the compiler 
+// or OS 
+void epicsAtomicReadMemoryBarrier ()
+{
+    EpicsAtomicLockKey key;
+    epicsAtomicLock ( & key  );
+    epicsAtomicUnlock ( & key  );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
+// Slow, but probably correct on all systems.
+// Useful only if something more efficent isnt 
+// provided based on knowledge of the compiler 
+// or OS 
+void epicsAtomicWriteMemoryBarrier ()
+{
+    EpicsAtomicLockKey key;
+    epicsAtomicLock ( & key  );
+    epicsAtomicUnlock ( & key  );
+}
+#endif
+

=== added file 'src/libCom/osi/os/posix/epicsAtomicOSD.h'
--- src/libCom/osi/os/posix/epicsAtomicOSD.h	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/posix/epicsAtomicOSD.h	2011-09-02 23:09:24 +0000
@@ -0,0 +1,35 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#ifndef epicsAtomicOSD_h
+#define epicsAtomicOSD_h
+
+struct EpicsAtomicLockKey {};
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * );
+epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * );
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+#include "epicsAtomicDefault.h"
+
+#endif /* epicsAtomicOSD_h */
+

=== 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-09-02 23:09:24 +0000
@@ -0,0 +1,178 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#ifndef epicsAtomicOSD_h
+#define epicsAtomicOSD_h
+
+#if defined ( __SunOS_5_10 )
+
+/* 
+ * atomic.h exists only in Solaris 10 or higher
+ */
+#include <sys/atomic.h>
+
+#include "epicsAssert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
+#define EPICS_ATOMIC_READ_MEMORY_BARRIER
+EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()  
+{
+    membar_consumer ();
+}
+#endif
+
+#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
+#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
+EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()  
+{
+    membar_producer ();
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_INTT
+#define EPICS_ATOMIC_CAS_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, 
+                                               int oldVal, int newVal )
+{
+    STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) );
+    unsigned * const pTarg = ( unsigned * ) pTarget;
+    return ( int ) atomic_cas_uint ( pTarg, ( unsigned ) oldVal, 
+                                        ( unsigned ) newVal );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_SIZET
+#define EPICS_ATOMIC_CAS_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( 
+                                                  size_t * pTarget,
+                                                  size_t oldVal, size_t newVal )
+{
+    STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) );
+    void ** const ppPtr = (void **) pTarget;
+    return ( size_t ) atomic_cas_ptr ( ppPtr, ( void * )oldVal, ( void * )newVal );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_PTRT
+#define EPICS_ATOMIC_CAS_PTRT
+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( 
+                                       EpicsAtomicPtrT * pTarget, 
+                                       EpicsAtomicPtrT oldVal, 
+                                       EpicsAtomicPtrT newVal )
+{
+    return atomic_cas_ptr ( pTarget, oldVal, newVal );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_INCR_INTT
+#define EPICS_ATOMIC_INCR_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
+{
+    STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) );
+    unsigned * const pTarg = ( unsigned * ) ( pTarget );
+    return ( int ) atomic_inc_uint_nv ( pTarg );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_INCR_SIZET
+#define EPICS_ATOMIC_INCR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
+{
+    STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) );
+    void ** const ppTarg = ( void ** ) ( pTarget );
+    return ( size_t ) atomic_inc_ptr_nv ( ppTarg );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_DECR_INTT
+#define EPICS_ATOMIC_DECR_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
+{
+    STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) );
+    unsigned * const pTarg = ( unsigned * ) ( pTarget );
+    return ( int ) atomic_dec_uint_nv ( pTarg );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_DECR_SIZET
+#define EPICS_ATOMIC_DECR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
+{
+    STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) );
+    void ** const pTarg = ( void ** ) ( pTarget );
+    return ( size_t ) atomic_dec_ptr_nv ( pTarg );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_ADD_INTT
+#define EPICS_ATOMIC_ADD_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
+{
+    STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) );
+    unsigned * const pTarg = ( unsigned * ) ( pTarget );
+    return ( int ) atomic_add_int_nv ( pTarg, delta );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_ADD_SIZET
+#define EPICS_ATOMIC_ADD_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, 
+                                                 size_t delta )
+{
+    STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) );
+    void ** const pTarg = ( void ** ) ( pTarget );
+    return ( size_t ) atomic_add_ptr_nv ( pTarg, ( ssize_t ) delta );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_SUB_SIZET
+#define EPICS_ATOMIC_SUB_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, 
+                                                 size_t delta )
+{
+    STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) );
+    void ** const pTarg = ( void ** ) ( pTarget );
+    ssize_t sdelta = ( ssize_t ) delta;
+    return ( size_t ) atomic_add_ptr_nv ( pTarg, -sdelta );
+}
+#endif
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+#endif /* ifdef __SunOS_5_10 */
+
+struct EpicsAtomicLockKey {};
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * );
+epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * );
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+#include "epicsAtomicDefault.h"
+
+#endif /* epicsAtomicOSD_h */
+

=== added file 'src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp'
--- src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp	1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp	2011-09-02 23:09:24 +0000
@@ -0,0 +1,21 @@
+
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#define epicsExportSharedSymbols
+#include "epicsAtomic.h"
+
+// if the compiler is unable to inline then instantiate out-of-line
+#ifndef EPICS_ATOMIC_INLINE
+#   define EPICS_ATOMIC_INLINE
+#   include "epicsAtomicOSD.h"
+#endif

=== 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-09-02 23:09:24 +0000
@@ -0,0 +1,251 @@
+/*************************************************************************\
+* 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
+ *  [email protected]
+ */
+
+#ifndef epicsAtomicOSD_h
+#define epicsAtomicOSD_h
+
+#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 */
+
+#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
+#define EPICS_ATOMIC_READ_MEMORY_BARRIER
+EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () 
+{
+    VX_MEM_BARRIER_R ();
+}
+#endif
+
+#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
+#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
+EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () 
+{
+    VX_MEM_BARRIER_W ();
+}
+#endif
+
+/*
+ * we make the probably correct guess that if ULONG_MAX 
+ * is the same as UINT_MAX then sizeof ( atomic_t )
+ * 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 ) );
+STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( EpicsAtomicPtrT ) );
+
+
+#ifndef EPICS_ATOMIC_INCR_SIZET
+#define EPICS_ATOMIC_INCR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
+{
+    atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
+    const atomic_t oldVal = vxAtomicInc ( pTarg );
+    return 1 + ( size_t ) ( oldVal );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_DECR_SIZET
+#define EPICS_ATOMIC_DECR_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
+{
+    atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
+    const atomic_t oldVal = vxAtomicDec ( pTarg );
+    return ( ( size_t ) oldVal ) - 1u;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_ADD_SIZET
+#define EPICS_ATOMIC_ADD_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
+{
+    /* 
+     * vxAtomicLib doc indicates that vxAtomicAdd is 
+     * implemented using signed arithmetic, but it
+     * does not change the end result because twos
+     * complement addition is used in either case
+     */
+    atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
+    const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta );
+    return delta + ( size_t ) oldVal;
+} 
+#endif 
+
+#ifndef EPICS_ATOMIC_SUB_SIZET
+#define EPICS_ATOMIC_SUB_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
+{
+    /* 
+     * vxAtomicLib doc indicates that vxAtomicSub is 
+     * implemented using signed arithmetic, but it
+     * does not change the end result because twos
+     * complement subtraction is used in either case
+     */
+    atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
+    const atomic_t oldVal = vxAtomicSub ( pTarg, (atomic_t) delta );
+    return ( ( size_t ) oldVal ) - delta;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_SIZET
+#define EPICS_ATOMIC_CAS_SIZET
+EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, 
+                            size_t oldVal, size_t newVal )
+{
+    atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
+    return ( size_t ) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_PTRT
+#define EPICS_ATOMIC_CAS_PTRT
+EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, 
+                            EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
+{
+    atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
+    return (EpicsAtomicPtrT) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
+}
+#endif
+
+#else /* ULONG_MAX == UINT_MAX */
+
+/*
+ * if its 64 bit SMP vxWorks and the compiler doesnt
+ * have an intrinsic then maybe there isnt any way to 
+ * implement these without using a global lock because 
+ * size_t is maybe bigger than atomic_t
+ *
+ * I dont yet have access to vxWorks manuals for 
+ * 64 bit systems so this is still undecided, but is
+ * defaulting now to a global lock
+ */
+
+#endif /* ULONG_MAX == UINT_MAX */
+
+STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( int ) );
+
+#ifndef EPICS_ATOMIC_INCR_INTT
+#define EPICS_ATOMIC_INCR_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
+{
+    atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
+    const atomic_t oldVal = vxAtomicInc ( pTarg );
+    return 1 + ( int ) oldVal;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_DECR_INTT
+#define EPICS_ATOMIC_DECR_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
+{
+    atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
+    const atomic_t oldVal = vxAtomicDec ( pTarg );
+    return ( ( int ) oldVal ) - 1;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_ADD_INTT
+#define EPICS_ATOMIC_ADD_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
+{
+    atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
+    const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta );
+    return delta + ( int ) oldVal;
+}
+#endif
+
+#ifndef EPICS_ATOMIC_CAS_INTT
+#define EPICS_ATOMIC_CAS_INTT
+EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, 
+                                            int oldVal, int newVal )
+{
+    atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
+    return ( int ) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
+}
+#endif
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+#else /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
+
+#include "vxLib.h"
+#include "intLib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef EPICS_ATOMIC_LOCK
+#define EPICS_ATOMIC_LOCK
+
+typedef struct EpicsAtomicLockKey { int m_key; } EpicsAtomicLockKey;
+
+EPICS_ATOMIC_INLINE void epicsAtomicLock ( EpicsAtomicLockKey * pKey )
+{
+    pKey->m_key = intLock ();
+}
+
+EPICS_ATOMIC_INLINE void epicsAtomicUnlock ( EpicsAtomicLockKey * pKey )
+{
+    intUnlock ( pKey->m_key );
+}
+#endif
+
+#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
+#define EPICS_ATOMIC_READ_MEMORY_BARRIER
+/* 
+ * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system 
+ * (we are not protecting against multiple access to memory mapped IO)
+ */
+EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () {}
+#endif
+
+#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
+#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
+/* 
+ * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system 
+ * (we are not protecting against multiple access to memory mapped IO)
+ */
+EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () {}
+#endif
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+#endif /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
+
+#include "epicsAtomicDefault.h"
+
+#endif /* epicsAtomicOSD_h */
+

=== modified file 'src/libCom/test/Makefile'
--- src/libCom/test/Makefile	2011-08-30 23:09:11 +0000
+++ src/libCom/test/Makefile	2011-09-02 23:09:24 +0000
@@ -108,6 +108,11 @@
 testHarness_SRCS += epicsMutexTest.cpp
 TESTS += epicsMutexTest
 
+TESTPROD_HOST += epicsAtomicTest
+epicsAtomicTest_SRCS += epicsAtomicTest.cpp
+testHarness_SRCS += epicsAtomicTest.cpp
+TESTS += epicsAtomicTest
+
 TESTPROD_HOST += epicsExceptionTest
 epicsExceptionTest_SRCS += epicsExceptionTest.cpp
 testHarness_SRCS += epicsExceptionTest.cpp
@@ -178,6 +183,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-09-02 23:09:24 +0000
@@ -0,0 +1,506 @@
+
+#include <cstdlib>
+#include <cstdio>
+#include <cassert>
+#include <typeinfo>
+
+#include "epicsInterrupt.h"
+#include "epicsAtomic.h"
+#include "epicsTime.h"
+#include "epicsUnitTest.h"
+#include "testMain.h"
+
+using std :: size_t;
+using namespace epics; 
+using namespace atomic;
+
+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;
+
+template < class T >
+class OrdinaryIncr {
+public:
+    OrdinaryIncr () : m_target ( 0 ) {}
+    void run ();
+    void diagnostic ( double delay );
+private:	
+    T m_target;
+};
+
+// tests the time it takes to perform a call to an external 
+// function and also increment an integer word. The 
+// epicsInterruptIsInterruptContext function is an 
+// out-of-line function implemented in a sharable library 
+// so hopefully it wont be optimized away.
+template < class T >
+inline void OrdinaryIncr < T > :: run ()
+{
+    m_target += epicsInterruptIsInterruptContext ();
+    m_target += epicsInterruptIsInterruptContext ();
+    m_target += epicsInterruptIsInterruptContext ();
+    m_target += epicsInterruptIsInterruptContext ();
+    m_target += epicsInterruptIsInterruptContext ();
+    m_target += epicsInterruptIsInterruptContext ();
+    m_target += epicsInterruptIsInterruptContext ();
+    m_target += epicsInterruptIsInterruptContext ();
+    m_target += epicsInterruptIsInterruptContext ();
+    m_target += epicsInterruptIsInterruptContext ();
+}
+
+template < class T >
+void OrdinaryIncr < T > :: diagnostic ( double delay )
+{
+    delay /= 10.0;
+    delay *= 1e6;
+    const char * const pName = typeid ( T ) . name ();
+    testDiag ( "raw incr of \"%s\" and a NOOP function call takes %f microseconds", 
+                         pName, delay );
+}
+
+template < class T >
+class AtomicIncr {
+public:
+    AtomicIncr () : m_target ( 0 ) {}
+    void run ();
+    void diagnostic ( double delay );
+private:	
+    T m_target;
+};
+
+template < class T >
+inline void AtomicIncr < T > :: run ()
+{
+    increment ( m_target );
+    increment ( m_target );
+    increment ( m_target );
+    increment ( m_target );
+    increment ( m_target );
+    increment ( m_target );
+    increment ( m_target );
+    increment ( m_target );
+    increment ( m_target );
+    increment ( m_target );
+}
+
+template < class T >
+void AtomicIncr < T > :: diagnostic ( double delay )
+{
+    delay /= 10.0;
+    delay *= 1e6;
+    const char * const pName = typeid ( T ) . name ();
+    testDiag ( "epicsAtomicIncr \"%s\" takes %f microseconds", 
+                        pName, delay );
+}
+
+template < class T > T trueValue ();
+template < class T > T falseValue ();
+
+// int
+template <>
+inline int trueValue < int > () { return 1; }
+
+template <>
+inline int falseValue < int > () { return 0; }
+
+// size_t 
+template <>
+inline size_t trueValue < size_t > () { return 1u; }
+
+template <>
+inline size_t falseValue < size_t > () { return 0u; }
+
+// EpicsAtomicPtrT
+template <>
+inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > () 
+{ static char c; return & c; }
+
+template <>
+inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > () 
+{ return 0u; }
+
+template < class T >
+class AtomicCmpAndSwap {
+public:
+    AtomicCmpAndSwap () : m_target ( 0 ) {}
+    void run ();
+    void diagnostic ( double delay );
+private:	
+    T m_target;
+};
+
+template < class T >
+inline void AtomicCmpAndSwap < T > :: run ()
+{
+    compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
+    compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
+    compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
+    compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
+    compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
+    compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
+    compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
+    compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
+    compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
+    compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
+}
+
+template < class T >
+void AtomicCmpAndSwap < T > :: diagnostic ( double delay )
+{
+    delay /= 10.0;
+    delay *= 1e6;
+    const char * const pName = typeid ( T ) . name ();
+    testDiag ( "epicsAtomicCmpAndSwap of \"%s\" takes %f microseconds", 
+                         pName, delay );
+}
+
+template < class T >
+class AtomicSet {
+public:
+    AtomicSet () : m_target ( 0 ) {}
+    void run ();
+    void diagnostic ( double delay );
+private:	
+    T m_target;
+};
+
+template < class T >
+inline void AtomicSet < T > :: run ()
+{
+    set ( m_target, 0 );
+    set ( m_target, 0 );
+    set ( m_target, 0 );
+    set ( m_target, 0 );
+    set ( m_target, 0 );
+    set ( m_target, 0 );
+    set ( m_target, 0 );
+    set ( m_target, 0 );
+    set ( m_target, 0 );
+    set ( m_target, 0 );
+}
+
+template < class T >
+void AtomicSet < T > :: diagnostic ( double delay )
+{
+    delay /= 10.0;
+    delay *= 1e6;
+    const char * const pName = typeid ( T ) . name ();
+    testDiag ( "epicsAtomicSet of \"%s\" takes %f microseconds", 
+		    pName, delay );
+}
+
+static const unsigned N = 10000;
+
+void recursiveOwnershipRetPerformance ()
+{
+    RefCtr refCtr;
+    epicsTime begin = epicsTime::getCurrent ();
+    for ( size_t 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 ( size_t 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 );
+}
+
+template < class T >
+class Ten 
+{
+public:
+    void run ();
+    void diagnostic ( double delay );
+    typedef Ten < Ten < T > > Hundred;
+    typedef Ten < Hundred > Thousand;
+private:
+    T m_target;
+};
+
+template < class T >
+inline void Ten < T > :: run ()
+{
+    m_target.run ();
+    m_target.run ();
+    m_target.run ();
+    m_target.run ();
+    m_target.run ();
+    m_target.run ();
+    m_target.run ();
+    m_target.run ();
+    m_target.run ();
+    m_target.run ();
+}
+
+template < class T >
+void Ten < T > :: diagnostic ( double delay )
+{
+    m_target.diagnostic ( delay / 10.0 );
+}
+
+template < class T >
+void measurePerformance ()
+{
+    epicsTime begin = epicsTime::getCurrent ();
+    T target;
+    for ( size_t i = 0; i < N; i++ ) {
+        target.run ();
+        target.run ();
+        target.run ();
+        target.run ();
+        target.run ();
+        target.run ();
+        target.run ();
+        target.run ();
+        target.run ();
+        target.run ();
+    }
+    double delay = epicsTime::getCurrent () -  begin;
+    delay /= ( N * 10u ); // convert to delay per call
+    target.diagnostic ( delay );
+}
+
+template < class T > 
+void measure ()
+{
+    measurePerformance < typename Ten < T > :: Hundred > ();
+}
+
+MAIN ( epicsAtomicPerform )
+{
+    testPlan ( 0 );
+    //
+    // The tests running here are measuring fast
+    // functions so they tend to be impacted
+    // by where the cache lines are wrt to the
+    // virtual pages perhap
+    //
+    measure < AtomicSet < int > > ();
+    measure < AtomicSet < size_t > > ();
+    measure < AtomicSet < void * > > ();
+    measure < OrdinaryIncr < int > > ();
+    measure < OrdinaryIncr < size_t > > ();
+    measure < AtomicIncr < int > > ();
+    measure < AtomicIncr < size_t > > ();
+    measure < AtomicCmpAndSwap < int > > ();
+    measure < AtomicCmpAndSwap < size_t > > ();
+    measure < AtomicCmpAndSwap < void * > > ();
+    recursiveOwnershipRetPerformance ();
+    ownershipPassRefPerformance ();
+    return testDone();
+}

=== added file 'src/libCom/test/epicsAtomicTest.cpp'
--- src/libCom/test/epicsAtomicTest.cpp	1970-01-01 00:00:00 +0000
+++ src/libCom/test/epicsAtomicTest.cpp	2011-09-02 23:09:24 +0000
@@ -0,0 +1,238 @@
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "epicsAtomic.h"
+#include "epicsTime.h"
+#include "epicsThread.h"
+#include "epicsUnitTest.h"
+#include "testMain.h"
+
+using namespace epics;
+using namespace atomic;
+
+template < class T >
+struct TestDataIncrDecr {
+    T m_testValue;
+    size_t m_testIterations;
+};
+
+template < class T >
+struct TestDataAddSub {
+    T m_testValue;
+    size_t m_testIterations;
+    static const T delta = 17;
+};
+
+template < class T >
+static void incr ( void *arg )
+{
+    TestDataIncrDecr < T > * const pTestData = 
+	    reinterpret_cast < TestDataIncrDecr < T > * > ( arg );
+    increment ( pTestData->m_testValue );
+    increment ( pTestData->m_testIterations );
+}
+
+template < class T >
+static void decr ( void *arg )
+{
+    TestDataIncrDecr < T > * const pTestData = 
+	    reinterpret_cast < TestDataIncrDecr < T > * > ( arg );
+    decrement ( pTestData->m_testValue );
+    increment ( pTestData->m_testIterations );
+}
+
+
+template < class T >
+static void add ( void *arg )
+{
+    TestDataAddSub < T > * const pTestData = 
+	    reinterpret_cast < TestDataAddSub < T > * > ( arg );
+    add ( pTestData->m_testValue, TestDataAddSub < T > :: delta  );
+    increment ( pTestData->m_testIterations );
+}
+
+template < class T >
+static void sub ( void *arg )
+{
+    TestDataAddSub < T > * const pTestData = 
+	    reinterpret_cast < TestDataAddSub < T > * > ( arg );
+    subtract ( pTestData->m_testValue, TestDataAddSub < T > :: delta );
+    increment ( pTestData->m_testIterations );
+}
+
+template < class T >
+struct TestDataCAS {
+    T m_testValue;
+    size_t m_testIterationsSet;
+    size_t m_testIterationsNotSet;
+};
+
+int isModulo ( size_t N, size_t n ) 
+{
+    return ( n % N ) == 0u;
+}
+
+template < class T >
+static T trueValue ();
+template < class T >
+static T falseValue ();
+
+// int
+template <>
+inline int trueValue < int > () { return 1; }
+
+template <>
+inline int falseValue < int > () { return 0; }
+
+// size_t 
+template <>
+inline size_t trueValue < size_t > () { return 1u; }
+
+template <>
+inline size_t falseValue < size_t > () { return 0u; }
+
+// EpicsAtomicPtrT
+template <>
+inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > () 
+{ static char c; return & c; }
+
+template <>
+inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > () 
+{ return 0u; }
+
+template < class T >
+static void cas ( void *arg )
+{
+    TestDataCAS < T > * const pTestData = 
+	    reinterpret_cast < TestDataCAS < T > * > ( arg );
+    /*
+     * intentionally waste cpu and maximize
+     * contention for the shared data
+     */
+    increment ( pTestData->m_testIterationsNotSet );
+    while ( ! compareAndSwap ( pTestData->m_testValue, 
+                                        falseValue < T > (), 
+                                        trueValue < T > () ) ) {
+    }
+    decrement ( pTestData->m_testIterationsNotSet );
+    set ( pTestData->m_testValue, falseValue < T > () );
+    increment ( pTestData->m_testIterationsSet );
+}
+
+template < class T >
+void testIncrDecr ()
+{
+    static const size_t N = 100;
+    static const T NT = static_cast < T > ( N );
+
+    const unsigned int stackSize = 
+        epicsThreadGetStackSize ( epicsThreadStackSmall );
+
+    TestDataIncrDecr < T > testData = { 0, N };
+    set ( testData.m_testValue, NT  );
+    testOk ( get ( testData.m_testValue ) == NT,
+	    "set/get %u", testData.m_testValue );
+    set ( testData.m_testIterations, 0u );
+    testOk ( get ( testData.m_testIterations ) == 0u,
+	    "set/get %u", testData.m_testIterations );
+    for ( size_t i = 0u; i < N; i++ ) {
+        epicsThreadCreate ( "incr",
+		    50, stackSize, incr < T >, & testData );
+        epicsThreadCreate ( "decr",
+		    50, stackSize, decr < T >, & testData );
+    }
+    while ( testData.m_testIterations < 2 * N ) {
+        epicsThreadSleep ( 0.01 );
+    }
+    testOk ( get ( testData.m_testIterations ) == 2 * N,
+	    "incr/decr iterations %u", 
+	    testData.m_testIterations );
+    testOk ( get ( testData.m_testValue ) == NT, 
+	    "incr/decr final value %u", 
+	    testData.m_testValue );
+}
+
+template < class T >
+void testAddSub ()
+{
+    static const size_t N = 100;
+    static const T NDT = TestDataAddSub < T > :: delta *
+	    				static_cast < T > ( N );
+
+    const unsigned int stackSize = 
+        epicsThreadGetStackSize ( epicsThreadStackSmall );
+
+    TestDataIncrDecr < T > testData = { 0, N };
+    set ( testData.m_testValue, NDT  );
+    testOk ( get ( testData.m_testValue ) == NDT,
+	    "set/get %u", testData.m_testValue );
+    set ( testData.m_testIterations, 0u );
+    testOk ( get ( testData.m_testIterations ) == 0u,
+	    "set/get %u", testData.m_testIterations );
+    for ( size_t i = 0u; i < N; i++ ) {
+        epicsThreadCreate ( "add",
+		    50, stackSize, add < T >, & testData );
+        epicsThreadCreate ( "sub",
+		    50, stackSize, sub < T >, & testData );
+    }
+    while ( testData.m_testIterations < 2 * N ) {
+        epicsThreadSleep ( 0.01 );
+    }
+    testOk ( get ( testData.m_testIterations ) == 2 * N,
+	    "add/sub iterations %u", 
+	    testData.m_testIterations );
+    testOk ( get ( testData.m_testValue ) == NDT, 
+	    "add/sub final value %u", 
+	    testData.m_testValue );
+}
+
+template < class T >
+void testCAS ()
+{
+	static const size_t N = 10;
+
+    const unsigned int stackSize = 
+        epicsThreadGetStackSize ( epicsThreadStackSmall );
+
+	TestDataCAS < T > testData = { 0, N, N };
+	set ( testData.m_testIterationsSet, 0 );
+	testOk ( get ( testData.m_testIterationsSet ) == 0u,
+				"set/get %u", testData.m_testIterationsSet );
+	set ( testData.m_testIterationsNotSet, 0 );
+	testOk ( get ( testData.m_testIterationsNotSet ) == 0u,
+				"set/get %u", testData.m_testIterationsNotSet );
+	set ( testData.m_testValue, trueValue < T > () );
+	testOk ( get ( testData.m_testValue ) == trueValue < T > (),
+				"set/get a true value" );
+	for ( size_t i = 0u; i < N; i++ ) {
+		epicsThreadCreate ( "tns",
+					50, stackSize, cas < T >, & testData );
+	}
+	set ( testData.m_testValue, falseValue < T > () );
+	while ( testData.m_testIterationsSet < N ) {
+		epicsThreadSleep ( 0.01 );
+	}
+	testOk ( get ( testData.m_testIterationsSet ) == N,
+				"test and set iterations %u", 
+				testData.m_testIterationsSet );
+	testOk ( get ( testData.m_testIterationsNotSet ) == 0u,
+				"test and set not-set tracking = %u", 
+				testData.m_testIterationsNotSet );
+}
+
+MAIN ( epicsAtomicTest )
+{
+
+    testPlan ( 31 );
+
+    testIncrDecr < int > ();
+    testIncrDecr < size_t > ();
+    testAddSub < int > ();
+    testAddSub < size_t > ();
+    testCAS < int > ();
+    testCAS < size_t > ();
+    testCAS < EpicsAtomicPtrT > ();
+
+    return testDone ();
+}


Replies:
Re: [Merge] lp:~epics-core/epics-base/rebased-atomics into lp:epics-base Andrew Johnson
Re: [Merge] lp:~epics-core/epics-base/rebased-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/rebased-atomics into lp:epics-base Jeff Hill
Re: [Merge] lp:~epics-core/epics-base/rebased-atomics into lp:epics-base Andrew Johnson
[Merge] lp:~epics-core/epics-base/rebased-atomics into lp:epics-base noreply

Navigate by Date:
Prev: Re: [Merge] lp:~epics-core/epics-base/epicsR3.15-atomics into lp:epics-base Andrew Johnson
Next: Re: [Merge] lp:~epics-core/epics-base/rebased-atomics into lp:epics-base Andrew Johnson
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: RE: Atomic operation library and spin-lock for the epics ring buffer Williams Jr., Ernest L.
Next: Re: [Merge] lp:~epics-core/epics-base/rebased-atomics into lp:epics-base Andrew Johnson
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
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 ·