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
<2011>
2012
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
<2011>
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
|