diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index 2b607de4b..c8809166c 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -45,6 +45,7 @@ INC += osiWireFormat.h INC += osdWireFormat.h INC += osdWireConfig.h INC += epicsAtomic.h +INC += epicsAtomicDefault.h INC += epicsAtomicLocked.h INC += epicsAtomicOSD.h INC += epicsAtomicCD.h @@ -131,6 +132,8 @@ Com_SRCS_vxWorks += logMsgToErrlog.cpp #This forces the vxWorks compatibility stuff to be loaded OBJS_vxWorks = vxComLibrary +INC_WIN32 += epicsAtomicMS.h + Com_SRCS_WIN32 += epicsGetopt.c Com_SRCS_WIN32 += setThreadName.cpp #Com_SRCS_WIN32 += dllmain.cpp diff --git a/src/libCom/osi/compiler/clang/epicsAtomicCD.h b/src/libCom/osi/compiler/clang/epicsAtomicCD.h index fea011561..54465d6f4 100644 --- a/src/libCom/osi/compiler/clang/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/clang/epicsAtomicCD.h @@ -17,9 +17,9 @@ #define epicsAtomicCD_h #if defined ( __cplusplus ) -# define OSD_ATOMIC_INLINE inline +# define EPICS_ATOMIC_INLINE inline #else -# define OSD_ATOMIC_INLINE __inline__ +# define EPICS_ATOMIC_INLINE __inline__ #endif #include "epicsAtomicOSD.h" diff --git a/src/libCom/osi/compiler/default/epicsAtomicCD.h b/src/libCom/osi/compiler/default/epicsAtomicCD.h index 60171e377..d07dfb24f 100644 --- a/src/libCom/osi/compiler/default/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/default/epicsAtomicCD.h @@ -17,7 +17,7 @@ #define epicsAtomicCD_h #if __STDC_VERSION__ >= 199901L || defined ( __cplusplus ) -# define OSD_ATOMIC_INLINE inline +# define EPICS_ATOMIC_INLINE inline #endif #include "epicsAtomicOSD.h" diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index 7e961386a..055d8be52 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -20,12 +20,12 @@ # error this header is only for use with the gnu compiler #endif -#define OSD_ATOMIC_INLINE __inline__ +#define EPICS_ATOMIC_INLINE __inline__ #define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B) #define GCC_ATOMIC_CONCATR( A, B ) ( A ## B ) -#define GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ +#define GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \ GCC_ATOMIC_CONCAT ( \ __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \ __SIZEOF_INT__ ) @@ -46,89 +46,127 @@ ( GCC_ATOMIC_INTRINSICS_MIN_X86 && \ GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER ) -#if ( GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \ - && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ - || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER - -#define OSD_ATOMIC_INLINE_DEFINITION - #ifdef __cplusplus extern "C" { #endif -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - return __sync_add_and_fetch ( pTarget, 1u ); -} +/* + * We are optimistic that __sync_synchronize is implemented + * in all version four gcc invarient of target. The gnu doc + * seems to say that when not supported by architecture a call + * to an external function is generated but in practice + * this isnt the case for some of the atomic intrinsics, and + * so there is an undefined symbol. So far we have not seen + * that with __sync_synchronize, but we can only guess based + * on experimental evidence. + * + * For example we know that when generating object code for + * 386 most of the atomic instrinsics are not present and + * we see undefined symbols with mingw, but we dont have + * troubles with __sync_synchronize. + */ +#if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - return __sync_sub_and_fetch ( pTarget, 1u ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, - size_t newValue ) -{ - *pTarget = newValue; - __sync_synchronize (); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, - unsigned newValue ) -{ - *pTarget = newValue; - __sync_synchronize (); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT newValue ) -{ - *pTarget = newValue; - __sync_synchronize (); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER +#define EPICS_ATOMIC_READ_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () { __sync_synchronize (); - return *pTarget; } +#endif -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER +#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () { __sync_synchronize (); - return *pTarget; } +#endif -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +#endif /* if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER */ + +#if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \ + || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER + +#define EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) { - __sync_synchronize (); - return *pTarget; + return __sync_add_and_fetch ( pTarget, 1 ); } -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) +#define EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) +{ + return __sync_sub_and_fetch ( pTarget, 1 ); +} + +#define EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) +{ + return __sync_add_and_fetch ( pTarget, delta ); +} + +#define EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ) { return __sync_val_compare_and_swap ( pTarget, oldVal, newVal); } -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, +#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T */ + +#if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \ + || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER + +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + return __sync_add_and_fetch ( pTarget, 1u ); +} + +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + return __sync_sub_and_fetch ( pTarget, 1u ); +} + +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) +{ + return __sync_add_and_fetch ( pTarget, delta ); +} + +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) +{ + return __sync_sub_and_fetch ( pTarget, delta ); +} + +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldVal, size_t newVal ) +{ + return __sync_val_compare_and_swap ( pTarget, oldVal, newVal); +} + +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { return __sync_val_compare_and_swap ( pTarget, oldVal, newVal); } +#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T */ + #ifdef __cplusplus } /* end of extern "C" */ #endif -#else /* if GCC_ATOMIC_INTRINSICS_AVAIL */ - - /* - * not available as gcc intrinsics so we - * will employ an os specific inline solution - */ -# include "epicsAtomicOSD.h" - -#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL */ +/* + * if currently unavailable as gcc intrinsics we + * will try for an os specific inline solution + */ +#include "epicsAtomicOSD.h" #endif /* epicsAtomicCD_h */ diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index fa3ba8a81..ca9295f73 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -26,178 +26,99 @@ #include -#pragma intrinsic ( _InterlockedExchange ) -#pragma intrinsic ( _InterlockedCompareExchange ) -#pragma intrinsic ( _InterlockedIncrement ) -#pragma intrinsic ( _InterlockedDecrement ) -#pragma intrinsic ( _InterlockedExchange ) -#pragma intrinsic ( _InterlockedExchangeAdd ) -#if OSD_ATOMIC_64 -# pragma intrinsic ( _InterlockedIncrement64 ) -# pragma intrinsic ( _InterlockedDecrement64 ) -# pragma intrinsic ( _InterlockedExchange64 ) -# pragma intrinsic ( _InterlockedExchangeAdd64 ) -#endif - #if _MSC_VER >= 1200 -# define OSD_ATOMIC_INLINE __forceinline +# define EPICS_ATOMIC_INLINE __forceinline #else -# define OSD_ATOMIC_INLINE __inline +# define EPICS_ATOMIC_INLINE __inline #endif #if defined ( _M_IX86 ) # pragma warning( push ) # pragma warning( disable : 4793 ) - OSD_ATOMIC_INLINE void OSD_ATOMIC_SYNC () + EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier () { long fence; __asm { xchg fence, eax } } # pragma warning( pop ) #elif defined ( _M_X64 ) -# define OSD_ATOMIC_64 +# define MS_ATOMIC_64 # pragma intrinsic ( __faststorefence ) -# define OSD_ATOMIC_SYNC __faststorefence + EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier () + { + __faststorefence (); + } #elif defined ( _M_IA64 ) -# define OSD_ATOMIC_64 +# define MS_ATOMIC_64 # pragma intrinsic ( __mf ) -# define OSD_ATOMIC_SYNC __mf + EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier () + { + __mf (); + } #else # error unexpected target architecture, msvc version of epicsAtomicCD.h #endif -#define OSD_ATOMIC_INLINE_DEFINITION - /* * The windows doc appears to recommend defining InterlockedExchange * to be _InterlockedExchange to cause it to be an intrinsic, but that * creates issues when later, in a windows os specific header, we include - * windows.h so we except some code duplication between the msvc csAtomic.h - * and win32 osdAtomic.h to avoid problems, and to keep the os specific - * windows.h header file out of the msvc cdAtomic.h + * windows.h. Therefore, we except some code duplication between the msvc + * csAtomic.h and win32 osdAtomic.h to avoid problems, and to keep the + * os specific windows.h header file out of the msvc cdAtomic.h */ +#define MS_LONG long +#define MS_InterlockedExchange _InterlockedExchange +#define MS_InterlockedCompareExchange _InterlockedCompareExchange +#define MS_InterlockedIncrement _InterlockedIncrement +#define MS_InterlockedDecrement _InterlockedDecrement +#define MS_InterlockedExchange _InterlockedExchange +#define MS_InterlockedExchangeAdd _InterlockedExchangeAdd +#if defined ( MS_ATOMIC_64 ) +# define MS_LONGLONG long long +# define MS_InterlockedIncrement64 _InterlockedIncrement64 +# define MS_InterlockedDecrement64 _InterlockedDecrement64 +# define MS_InterlockedExchange64 _InterlockedExchange64 +# define MS_InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +# define MS_InterlockedCompareExchange64 _InterlockedCompareExchange64 +#endif + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/* necessary for next three functions */ -STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) ); - -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +#define EPICS_ATOMIC_READ_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () { - *pTarget = newVal; - OSD_ATOMIC_SYNC (); + epicsAtomicMemoryBarrier (); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () { - *pTarget = newVal; - OSD_ATOMIC_SYNC (); + epicsAtomicMemoryBarrier (); } -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT newVal ) -{ - *pTarget = newVal; - OSD_ATOMIC_SYNC (); -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) -{ - OSD_ATOMIC_SYNC (); - return *pTarget; -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - OSD_ATOMIC_SYNC (); - return *pTarget; -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - OSD_ATOMIC_SYNC (); - return *pTarget; -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) -{ - long * const pTarg = ( long * ) ( pTarget ); - return (unsigned) _InterlockedCompareExchange ( pTarg, - (long) newVal, (long) oldVal ); -} - -#if ! OSD_ATOMIC_64 - -/* - * necessary for next five functions - * - * looking at the MS documentation it appears that they will - * keep type long the same size as an int on 64 bit builds - */ -STATIC_ASSERT ( sizeof ( long ) == sizeof ( size_t ) ); - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - long * const pTarg = ( long * ) pTarget; - return _InterlockedIncrement ( pTarg ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - long * const pTarg = ( long * ) ( pTarget ); - return _InterlockedDecrement ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - long * const pTarg = ( long * ) ( pTarget ); - return (EpicsAtomicPtrT) _InterlockedCompareExchange ( pTarg, - (long) newVal, (long) oldVal ); -} - -#else /* ! OSD_ATOMIC_64 */ - -/* - * necessary for next five functions - */ -STATIC_ASSERT ( sizeof ( long long ) == sizeof ( size_t ) ); - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - long long * const pTarg = ( long long * ) pTarget; - return _InterlockedIncrement64 ( pTarg ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - long long * const pTarg = ( long long * ) ( pTarget ); - return _InterlockedDecrement64 ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - long long * const pTarg = ( longlong * ) ( pTarget ); - return (EpicsAtomicPtrT) _InterlockedCompareExchange64 ( pTarg, - (long long) newVal, (long long) oldVal ); -} - -#endif /* ! OSD_ATOMIC_64 */ - #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ +#include "epicsAtomicMS.h" +#include "epicsAtomicDefault.h" + #else /* ifdef _MSC_EXTENSIONS */ #if defined ( __cplusplus ) -# define OSD_ATOMIC_INLINE inline -# include "epicsAtomicOSD.h" +# define EPICS_ATOMIC_INLINE inline #endif +/* + * if unavailable as an intrinsic we will try + * for os specific solution + */ +#include "epicsAtomicOSD.h" + #endif /* ifdef _MSC_EXTENSIONS */ #endif /* epicsAtomicCD_h */ + diff --git a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h index c72a3e203..e247a5e49 100644 --- a/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/solStudio/epicsAtomicCD.h @@ -17,9 +17,9 @@ #define epicsAtomicCD_h #if defined ( __cplusplus ) -# define OSD_ATOMIC_INLINE inline +# define EPICS_ATOMIC_INLINE inline #else -# define OSD_ATOMIC_INLINE __inline +# define EPICS_ATOMIC_INLINE __inline #endif #include "epicsAtomicOSD.h" diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index aa389ea2f..436da7bd0 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -25,60 +25,69 @@ extern "C" { typedef void * EpicsAtomicPtrT; +/* load target into cache */ +epicsShareFunc void epicsAtomicReadMemoryBarrier (); + +/* push cache version of target into target */ +epicsShareFunc void epicsAtomicWriteMemoryBarrier (); + /* * lock out other smp processors from accessing the target, - * sync target in cache, add one to target, flush target in - * cache, allow other smp processors to access the target, + * load target into cache, add one to target, flush cache + * to target, allow other smp processors to access the target, * return new value of target as modified by this operation - * - * increment is chosen as the primitive here because, - * compared to add, it is more likely to be implemented - * atomically on old architectures such as 68k */ epicsShareFunc size_t epicsAtomicIncrSizeT ( size_t * pTarget ); +epicsShareFunc int epicsAtomicIncrIntT ( int * pTarget ); /* * lock out other smp processors from accessing the target, - * sync target in cache, subtract one from target, flush target - * in cache, allow out other smp processors to access the target, + * load target into cache, subtract one from target, flush cache + * to target, allow out other smp processors to access the target, * return new value of target as modified by this operation - * - * decrement is chosen as the primitive here because, - * compared to subtract, it is more likely to be implemented - * atomically on old architectures such as 68k */ epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget ); +epicsShareFunc int epicsAtomicDecrIntT ( int * pTarget ); /* - * set target in cache, flush target in cache + * lock out other smp processors from accessing the target, + * load target into cache, add/sub delta to/from target, flush cache + * to target, allow other smp processors to access the target, + * return new value of target as modified by this operation + */ +epicsShareFunc size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ); +epicsShareFunc size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ); +epicsShareFunc int epicsAtomicAddIntT ( int * pTarget, int delta ); + +/* + * set cache version of target, flush cache to target */ epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue ); -epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue ); +epicsShareFunc void epicsAtomicSetIntT ( int * pTarget, int newValue ); epicsShareFunc void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue ); /* - * fetch target in cache, return new value of target + * fetch target into cache, return new value of target */ epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget ); -epicsShareFunc unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ); +epicsShareFunc int epicsAtomicGetIntT ( const int * pTarget ); epicsShareFunc EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ); /* * lock out other smp processors from accessing the target, - * sync target in cache, if target is equal to oldVal set target - * to newVal, flush target in cache, allow other smp processors + * load target into cache, if target is equal to oldVal set target + * to newVal, flush cache to target, allow other smp processors * to access the target, return the original value stored in the * target - * - * !!!! beware, this will not guarantee an atomic operation - * !!!! on legacy vxWorks (prior to 6.6) if the target operand - * !!!! is on a multi-commander bus (such as the VME bus) */ -epicsShareFunc unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ); -epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); - +epicsShareFunc size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldVal, size_t newVal ); +epicsShareFunc int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ); +epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, + EpicsAtomicPtrT newVal ); #ifdef __cplusplus } /* end of extern "C" */ @@ -87,7 +96,141 @@ epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTa /* * options for inline compiler instrinsic or os specific * implementations of the above function prototypes + * + * its importnat for certaiin compiler to define the + * inline functions before they get used in the c++ + * code below */ #include "epicsAtomicCD.h" +#ifdef __cplusplus + +namespace epics { +namespace atomic { + +/* + * overloaded c++ interface + */ +epicsShareFunc size_t increment ( size_t & v ); +epicsShareFunc int increment ( int & v ); +epicsShareFunc size_t decrement ( size_t & v ); +epicsShareFunc int decrement ( int & v ); +epicsShareFunc size_t add ( size_t & v, size_t delta ); +epicsShareFunc int add ( int & v, int delta ); +epicsShareFunc size_t subtract ( size_t & v, size_t delta ); +epicsShareFunc int subtract ( int & v, int delta ); +epicsShareFunc void set ( size_t & v , size_t newValue ); +epicsShareFunc void set ( int & v, int newValue ); +epicsShareFunc void set ( EpicsAtomicPtrT & v, + EpicsAtomicPtrT newValue ); +epicsShareFunc size_t get ( const size_t & v ); +epicsShareFunc int get ( const int & v ); +epicsShareFunc EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v ); +epicsShareFunc size_t compareAndSwap ( size_t & v, size_t oldVal, + size_t newVal ); +epicsShareFunc int compareAndSwap ( int & v, int oldVal, int newVal ); +epicsShareFunc EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v, + EpicsAtomicPtrT oldVal, + EpicsAtomicPtrT newVal ); + +/************* incr ***************/ +inline size_t increment ( size_t & v ) +{ + return epicsAtomicIncrSizeT ( & v ); +} + +inline int increment ( int & v ) +{ + return epicsAtomicIncrIntT ( & v ); +} + +/************* decr ***************/ +inline size_t decrement ( size_t & v ) +{ + return epicsAtomicDecrSizeT ( & v ); +} + +inline int decrement ( int & v ) +{ + return epicsAtomicDecrIntT ( & v ); +} + +/************* add ***************/ +inline size_t add ( size_t & v, size_t delta ) +{ + return epicsAtomicAddSizeT ( & v, delta ); +} + +inline int add ( int & v, int delta ) +{ + return epicsAtomicAddIntT ( & v, delta ); +} + +/************* sub ***************/ +inline size_t subtract ( size_t & v, size_t delta ) +{ + return epicsAtomicSubSizeT ( & v, delta ); +} + +inline int subtract ( int & v, int delta ) +{ + return epicsAtomicAddIntT ( & v, -delta ); +} + +/************* set ***************/ +inline void set ( size_t & v , size_t newValue ) +{ + epicsAtomicSetSizeT ( & v, newValue ); +} + +inline void set ( int & v, int newValue ) +{ + epicsAtomicSetIntT ( & v, newValue ); +} + +inline void set ( EpicsAtomicPtrT & v, EpicsAtomicPtrT newValue ) +{ + epicsAtomicSetPtrT ( & v, newValue ); +} + +/************* get ***************/ +inline size_t get ( const size_t & v ) +{ + return epicsAtomicGetSizeT ( & v ); +} + +inline int get ( const int & v ) +{ + return epicsAtomicGetIntT ( & v ); +} + +inline EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v ) +{ + return epicsAtomicGetPtrT ( & v ); +} + +/************* cas ***************/ +inline size_t compareAndSwap ( size_t & v, + size_t oldVal, size_t newVal ) +{ + return epicsAtomicCmpAndSwapSizeT ( & v, oldVal, newVal ); +} + +inline int compareAndSwap ( int & v, int oldVal, int newVal ) +{ + return epicsAtomicCmpAndSwapIntT ( & v, oldVal, newVal ); +} + +inline EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v, + EpicsAtomicPtrT oldVal, + EpicsAtomicPtrT newVal ) +{ + return epicsAtomicCmpAndSwapPtrT ( & v, oldVal, newVal ); +} + +} /* end of namespace atomic */ +} /* end of namespace epics */ + +#endif /* ifdef __cplusplus */ + #endif /* epicsAtomic_h */ diff --git a/src/libCom/osi/epicsAtomicDefault.h b/src/libCom/osi/epicsAtomicDefault.h new file mode 100644 index 000000000..ff1f91114 --- /dev/null +++ b/src/libCom/osi/epicsAtomicDefault.h @@ -0,0 +1,235 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomicDefault_h +#define epicsAtomicDefault_h + +/* + * EPICS_ATOMIC_INLINE might be defined, but empty for an out-of-line + * instantiation + */ +#ifdef EPICS_ATOMIC_INLINE + +#ifdef __cpluplus +extern "C" { +#endif + +/* + * struct EpicsAtomicLockKey; + * epicsShareFunc void epicsAtomicReadMemoryBarrier (); + * epicsShareFunc void epicsAtomicWriteMemoryBarrier (); + * epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * ); + * epicsShareFunc void epicsAtomicUnock ( struct EpicsAtomicLockKey * ); + */ + +/* + * incr + */ +#ifndef EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const int result = ++(*pTarget); + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +#ifndef EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const size_t result = ++(*pTarget); + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +/* + * decr + */ +#ifndef EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const int result = --(*pTarget); + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +#ifndef EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const size_t result = --(*pTarget); + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +/* + * add/sub + */ +#ifndef EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const int result = *pTarget += delta; + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +#ifndef EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const size_t result = *pTarget += delta; + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +#ifndef EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const size_t result = *pTarget -= delta; + epicsAtomicUnlock ( & key ); + return result; +} +#endif + +/* + * set + */ +#ifndef EPICS_ATOMIC_SET_INTT +EPICS_ATOMIC_INLINE void epicsAtomicSetIntT ( int * pTarget, int newVal ) +{ + *pTarget = newVal; + epicsAtomicWriteMemoryBarrier (); +} +#endif + +#ifndef EPICS_ATOMIC_SET_SIZET +EPICS_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +{ + *pTarget = newVal; + epicsAtomicWriteMemoryBarrier (); +} +#endif + +#ifndef EPICS_ATOMIC_SET_PTRT +EPICS_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT newVal ) +{ + *pTarget = newVal; + epicsAtomicWriteMemoryBarrier (); +} +#endif + +/* + * get + */ +#ifndef EPICS_ATOMIC_GET_INTT +EPICS_ATOMIC_INLINE int epicsAtomicGetIntT ( const int * pTarget ) +{ + epicsAtomicReadMemoryBarrier (); + return *pTarget; +} +#endif + +#ifndef EPICS_ATOMIC_GET_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +{ + epicsAtomicReadMemoryBarrier (); + return *pTarget; +} +#endif + +#ifndef EPICS_ATOMIC_GET_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT + epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +{ + epicsAtomicReadMemoryBarrier (); + return *pTarget; +} +#endif + +/* + * cmp and swap + */ +#ifndef EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, int oldval, int newval ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const int cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + epicsAtomicUnlock ( & key ); + return cur; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldval, size_t newval ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const size_t cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + epicsAtomicUnlock ( & key ); + return cur; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + const EpicsAtomicPtrT cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + epicsAtomicUnlock ( & key ); + return cur; +} +#endif + +#ifdef __cpluplus +} /* end of extern "C" */ +#endif + +#endif /* EPICS_ATOMIC_INLINE */ + +#endif /* epicsAtomicDefault_h */ + + diff --git a/src/libCom/osi/epicsAtomicGuard.h b/src/libCom/osi/epicsAtomicGuard.h deleted file mode 100644 index b9cf2a74d..000000000 --- a/src/libCom/osi/epicsAtomicGuard.h +++ /dev/null @@ -1,55 +0,0 @@ - -/*************************************************************************\ -* Copyright (c) 2011 LANS LLC, as Operator of -* Los Alamos National Laboratory. -* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author Jeffrey O. Hill - * johill@lanl.gov - */ - -#ifndef epicsAtomicGuard_h -#define epicsAtomicGuard_h - -// -// This header file is intended only for use with the epicsAtomicLocked -// header file. The intent is that an OS specific implementation of -// epicsAtomicOSD.cpp might first include this file, next implement -// AtomicGuard depending on os specific capabilities, and finally include -// the epicsAtomicLocked header file to define the various epicsAtomicXxxx -// functions. -// -// The AtomicGuard class is defined in a seperate header file -// from the epicsAtomicLocked header for two reasons. -// o First, it must be possible to have an inline definition of the -// AtomicGuard member functions, and that isnt possible if the -// epicsAtomicXxxx function definitions in the epicsAtomicLocked -// header file have already been seen by the translation unit. -// o Second, we need to enforce a uniform interface for all definitions -// of the the AtomicGuard constructor and destructor member functions -// requiring that no exception are thrown. This is because the -// epicsAtomicXxxx functions in the epicsAtomicLocked header file are -// directly callable by C code. -// -// The epicsAtomicXxxx functions in the epicsAtomicLocked do not pass -// any parameters to the AtomicGuard constructor, and therefore the lock -// used by AtomicGuard is restricted to be a global lock for the entire -// multithreaded executable. Therefore, AtomicGuard will typically -// reference some translation unit scope limited global variable in -// the anonymous namespace for implementation of the locking primitive. -// - -namespace { - struct AtomicGuard { - AtomicGuard () throw (); - ~AtomicGuard () throw (); - }; -} // end of anonymous namespace - -#endif // ifndef epicsAtomicGuard_h - diff --git a/src/libCom/osi/epicsAtomicOSD.cpp b/src/libCom/osi/epicsAtomicOSD.cpp deleted file mode 100644 index a1b2ff4f5..000000000 --- a/src/libCom/osi/epicsAtomicOSD.cpp +++ /dev/null @@ -1,45 +0,0 @@ - -/*************************************************************************\ -* Copyright (c) 2011 LANS LLC, as Operator of -* Los Alamos National Laboratory. -* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author Jeffrey O. Hill - * johill@lanl.gov - */ - - #include "epicsAtomic.h" - - /* - * OSD_ATOMIC_INLINE - * defined: define atomic functions in osdAtomic.h - * undefined: dont define atomic functions in osdAtomic.h - * - * OSD_ATOMIC_INLINE is typically set by the compiler specific file cdAtomic.h - * - * when we discover here that there is no implementation, and we guess that - * there isnt an inline keyword in the compiler then we define OSD_ATOMIC_INLINE - * empty and include osdAtomic.h to force an out of line implementation - * - * My first inclination was to place only one file of this type under os/default, - * but then this source file always includes default/osdAtomic.h, which isnt correct - * if a more specific os/xxx/osdAtromic.h exists, and so rather than duplicate an - * identical file in all of the os directories (that will get rediculous if there - * is ever a posix interface for the atomics) I moved it here to the osi directory. - * Another option would be to not make tthe current location be the first search - * in the gnu make VPATH, but I am somewhat nervous about changing something that - * fundamental in the build system. - * - * this behavior will work most of the time by defualt but it can always be - * replaced by an os specific implementation, which might be required if - * some of the functions are inline and some are not - */ - #ifndef OSD_ATOMIC_INLINE - # include "osdAtomic.h" - #endif - diff --git a/src/libCom/osi/os/WIN32/epicsAtomicMS.h b/src/libCom/osi/os/WIN32/epicsAtomicMS.h new file mode 100644 index 000000000..bab1da4a4 --- /dev/null +++ b/src/libCom/osi/os/WIN32/epicsAtomicMS.h @@ -0,0 +1,222 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomicMS_h +#define epicsAtomicMS_h + +#include "epicsAssert.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef EPICS_ATOMIC_INCR_INTT +#define EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) pTarget; + return MS_InterlockedIncrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_INTT +#define EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return MS_InterlockedDecrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_ADD_INTT +#define EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + /* we dont use InterlockedAdd because only latest windows is supported */ + return delta + ( int ) MS_InterlockedExchangeAdd ( pTarg, + ( MS_LONG ) delta ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_INTT +#define EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ) +{ + STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) ); + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return (int) MS_InterlockedCompareExchange ( pTarg, + (MS_LONG) newVal, (MS_LONG) oldVal ); +} +#endif + +#if ! defined ( MS_ATOMIC_64 ) + +/* + * necessary for next three functions + * + * looking at the MS documentation it appears that they will + * keep type long the same size as an int on 64 bit builds + */ +STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( size_t ) ); + +#ifndef EPICS_ATOMIC_INCR_SIZET +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) pTarget; + return MS_InterlockedIncrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_SIZET +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return MS_InterlockedDecrement ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_ADD_SIZET +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, + size_t delta ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + /* we dont use InterlockedAdd because only latest windows is supported */ + return delta + ( size_t ) MS_InterlockedExchangeAdd ( pTarg, + ( MS_LONG ) delta ); +} +#endif + +#ifndef EPICS_ATOMIC_SUB_SIZET +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + MS_LONG ldelta = (MS_LONG) delta; + /* we dont use InterlockedAdd because only latest windows is supported */ + return ( ( size_t ) MS_InterlockedExchangeAdd ( pTarg, -ldelta ) ) - delta; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_SIZET +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( + size_t * pTarget, + size_t oldVal, size_t newVal ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return (size_t) MS_InterlockedCompareExchange ( pTarg, + (MS_LONG) newVal, (MS_LONG) oldVal ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_PTRT +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget ); + return (EpicsAtomicPtrT) MS_InterlockedCompareExchange ( pTarg, + (MS_LONG) newVal, (MS_LONG) oldVal ); +} +#endif + +#else /* ! MS_ATOMIC_64 */ + +/* + * necessary for next three functions + */ +STATIC_ASSERT ( sizeof ( MS_LONGLONG ) == sizeof ( size_t ) ); + +#ifndef EPICS_ATOMIC_INCR_SIZET +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) pTarget; + return ( size_t ) MS_InterlockedIncrement64 ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_SIZET +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + return ( size_t ) MS_InterlockedDecrement64 ( pTarg ); +} +#endif + +#ifndef EPICS_ATOMIC_ADD_SIZET +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + /* we dont use InterlockedAdd64 because only latest windows is supported */ + return delta + ( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, + ( MS_LONGLONG ) delta ); +} +#endif + +#ifndef EPICS_ATOMIC_SUB_SIZET +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + MS_LONGLONG ldelta = (MS_LONGLONG) delta; + /* we dont use InterlockedAdd64 because only latest windows is supported */ + return (( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, -ldelta )) - delta; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_SIZET +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldVal, size_t newVal ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + return (size_t) MS_InterlockedCompareExchange64 ( pTarg, + (MS_LONGLONG) newVal, + (MS_LONGLONG) oldVal ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_PTRT +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +{ + MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget ); + return (EpicsAtomicPtrT) MS_InterlockedCompareExchange64 ( pTarg, + (MS_LONGLONG) newVal, (MS_LONGLONG) oldVal ); +} +#endif + +#endif /* ! MS_ATOMIC_64 */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +#endif /* ifdef epicsAtomicMS_h */ + diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.cpp b/src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp similarity index 56% rename from src/libCom/osi/os/default/epicsAtomicOSD.cpp rename to src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp index ecb1ad7c9..b7f7b17c2 100644 --- a/src/libCom/osi/os/default/epicsAtomicOSD.cpp +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp @@ -14,13 +14,9 @@ #define epicsExportSharedSymbols #include "epicsAtomic.h" -// -// We need a default epicsAtopmicOSD.cpp which is empty for use when -// a compiler or inline OS specific implementation is provided. See -// "osi/os/posix/epicsAtomicOSD.cpp" for an example OS specific generic -// out-of-line implementation based on a mutex lock. -// -#if ! defined ( OSD_ATOMIC_INLINE_DEFINITION ) -# error the epicsAtomicXxxxx functions definitions are misssing +// if the compiler is unable to inline then instantiate out-of-line +#ifndef EPICS_ATOMIC_INLINE +#define EPICS_ATOMIC_INLINE +#include "epicsAtomic.h" #endif diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index bcf48facd..f9378c1c6 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -12,149 +12,38 @@ * Author Jeffrey O. Hill * johill@lanl.gov */ - + #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#if defined ( OSD_ATOMIC_INLINE ) - -#include - -#include "epicsAssert.h" - -#define STRICT #define VC_EXTRALEAN -#include +#define STRICT +#include "windows.h" -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +#if defined ( _WIN64 ) +# define MS_ATOMIC_64 +#endif -#define OSD_ATOMIC_INLINE_DEFINITION +#define MS_LONG LONG +#define MS_InterlockedExchange InterlockedExchange +#define MS_InterlockedCompareExchange InterlockedCompareExchange +#define MS_InterlockedIncrement InterlockedIncrement +#define MS_InterlockedDecrement InterlockedDecrement +#define MS_InterlockedExchange InterlockedExchange +#define MS_InterlockedExchangeAdd InterlockedExchangeAdd +#if defined ( MS_ATOMIC_64 ) +# define MS_LONGLONG LONGLONG +# define MS_InterlockedIncrement64 InterlockedIncrement64 +# define MS_InterlockedDecrement64 InterlockedDecrement64 +# define MS_InterlockedExchange64 InterlockedExchange64 +# define MS_InterlockedExchangeAdd64 InterlockedExchangeAdd64 +# define MS_InterlockedCompareExchange InterlockedCompareExchange64 +#endif -/* - * mingw doesnt currently provide MemoryBarrier - * (this is mostly for testing purposes as the gnu - * intrinsics are used if compiling for 486 or better - * minimum hardware) - */ -#ifdef __MINGW32__ - extern inline void MemoryBarrier() { - int fence = 0; - __asm__ __volatile__( "xchgl %%eax,%0 ":"=r" (fence) ); - } -#endif // ifdef __MINGW32__ +#ifdef EPICS_ATOMIC_INLINE +# include "epicsAtomicMS.h" +# include "epicsAtomicDefault.h" +#endif -/* necessary for next three functions */ -STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) ); +#endif /* epicsAtomicOSD_h */ -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) -{ - *pTarget = newVal; - MemoryBarrier (); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - *pTarget = newVal; - MemoryBarrier (); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - *pTarget = newVal; - MemoryBarrier (); -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) -{ - MemoryBarrier (); - return *pTarget; -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - MemoryBarrier (); - return *pTarget; -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - MemoryBarrier (); - return *pTarget; -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) -{ - LONG * const pTarg = ( LONG * ) ( pTarget ); - return (unsigned) InterlockedCompareExchange ( pTarg, - (LONG) newVal, (LONG) oldVal ); -} - -#if defined ( _WIN32 ) - -/* - * necessary for next five functions - * - * looking at the MS documentation it appears that they will - * keep type long the same size as an int on 64 bit builds - */ -STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( size_t ) ); - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - LONG * const pTarg = ( LONG * ) pTarget; - return InterlockedIncrement ( pTarg ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - LONG * const pTarg = ( LONG * ) ( pTarget ); - return InterlockedDecrement ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - LONG * const pTarg = ( LONG * ) ( pTarget ); - return (EpicsAtomicPtrT) InterlockedCompareExchange ( pTarg, - (LONG) newVal, (LONG) oldVal ); -} - -#elif defined ( _WIN64 ) - -/* - * necessary for next five functions - */ -STATIC_ASSERT ( sizeof ( LONGLONG ) == sizeof ( size_t ) ); - -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - LONGLONG * const pTarg = ( LONGLONG * ) pTarget; - return InterlockedIncrement64 ( pTarg ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); - return InterlockedDecrement64 ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget ); - return (EpicsAtomicPtrT) InterlockedCompareExchange64 ( pTarg, - (LONGLONG) newVal, (LONGLONG) oldVal ); -} - -#endif /* if defined ( _WIN32 ) */ - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif /* __cplusplus */ - -#endif /* if defined ( OSD_ATOMIC_INLINE ) */ - -#endif /* ifndef epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp index 5e182d748..2fb06c36f 100644 --- a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp @@ -9,67 +9,100 @@ /* * Author Jeffrey O. Hill * johill@lanl.gov - * - * Provide a global mutex version of AtomicGuard on POSIX - * systems for when we dont have more efficent compiler or - * OS primitives intriniscs to use instead. - * - * We implement this mutex-based AtomicGuard primitive directly - * upon the standalone POSIX pthread library so that the epicsAtomic - * library can be used to implement other primitives such - * epicsThreadOnce. - * - * We use a static initialized pthread mutex to minimize code - * size, and are also optimistic that this can be more efficent - * than pthread_once. */ +#define epicsExportSharedSymbols +#include "epicsAtomic.h" + +// if the compiler is unable to inline then instantiate out-of-line +#ifndef EPICS_ATOMIC_INLINE +#define EPICS_ATOMIC_INLINE +#include "epicsAtomic.h" +#endif + +/* Authors: Jeffrey O. Hill */ #include #include #include #define epicsExportSharedSymbols #include "epicsAssert.h" + +// if the compiler is unable to inline then instantiate out-of-line +#ifndef EPICS_ATOMIC_INLINE +#define EPICS_ATOMIC_INLINE #include "epicsAtomic.h" +#endif -// If we have an inline implementation then implement -// nothing that conflicts here -#if ! defined ( OSD_ATOMIC_INLINE_DEFINITION ) +#ifndef EPICS_ATOMIC_LOCK -// get the interface for class AtomicGuard -#include "epicsAtomicGuard.h" +/* + * Slow, but probably correct on all systems. + * Useful only if something more efficent isnt + * provided based on knowledge of the compiler + * or OS + * + * A statically initialized pthread mutex doesnt + * need to be destroyed + * + * !!!!! + * !!!!! WARNING + * !!!!! + * !!!!! Do not use this implementation on systems where + * !!!!! code runs at interrupt context. If so, then + * !!!!! an implementation must be provided that is based + * !!!!! on a compiler intrinsic or an interrpt lock and or + * !!!!! a spin lock primitive + * !!!!! + */ +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -namespace { - -// a statically initialized mutex doesnt need to be destroyed -pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -inline AtomicGuard :: AtomicGuard () throw () +void epicsAtomicLock ( EpicsAtomicLockKey * ) { unsigned countDown = 1000u; int status; while ( true ) { status = pthread_mutex_lock ( & mutex ); - if ( status != EINTR ) break; + if ( status == 0 ) return; + assert ( status == EINTR ); static const useconds_t retryDelayUSec = 100000; usleep ( retryDelayUSec ); countDown--; assert ( countDown ); } - assert ( status == 0 ); } -inline AtomicGuard :: ~AtomicGuard () throw () +void epicsAtomicUnlock ( EpicsAtomicLockKey * ) { const int status = pthread_mutex_unlock ( & mutex ); assert ( status == 0 ); } -} // end of namespace anonymous +#endif // ifndef EPICS_ATOMIC_LOCK -// Define the epicsAtomicXxxx functions out-of-line using this -// implementation of AtomicGuard. Note that this isnt a traditional -// c++ header file. -#include "epicsAtomicLocked.h" +#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER +// Slow, but probably correct on all systems. +// Useful only if something more efficent isnt +// provided based on knowledge of the compiler +// or OS +void epicsAtomicReadMemoryBarrier () +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + epicsAtomicUnlock ( & key ); +} +#endif + +#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER +// Slow, but probably correct on all systems. +// Useful only if something more efficent isnt +// provided based on knowledge of the compiler +// or OS +void epicsAtomicWriteMemoryBarrier () +{ + EpicsAtomicLockKey key; + epicsAtomicLock ( & key ); + epicsAtomicUnlock ( & key ); +} +#endif -#endif // if ! defined ( #define OSD_ATOMIC_INLINE_DEFINITION ) diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.h b/src/libCom/osi/os/posix/epicsAtomicOSD.h similarity index 61% rename from src/libCom/osi/os/default/epicsAtomicOSD.h rename to src/libCom/osi/os/posix/epicsAtomicOSD.h index bf09ae083..5446f23ef 100644 --- a/src/libCom/osi/os/default/epicsAtomicOSD.h +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.h @@ -16,4 +16,17 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h +struct EpicsAtomicLockKey {}; +epicsShareFunc void epicsAtomicReadMemoryBarrier (); +epicsShareFunc void epicsAtomicWriteMemoryBarrier (); +epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * ); +epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * ); + +#ifdef EPICS_ATOMIC_INLINE + +#include "epicsAtomicDefault.h" + +#endif /* ifdef EPICS_ATOMIC_INLINE */ + #endif /* epicsAtomicOSD_h */ + diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 48c95824a..e377a770b 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -16,84 +16,141 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#if defined ( OSD_ATOMIC_INLINE ) +#if defined ( EPICS_ATOMIC_INLINE ) /* * atomic.h exists only in Solaris 10 or higher */ #if defined ( __SunOS_5_10 ) -#include #include -#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ -#include - -#define OSD_ATOMIC_INLINE_DEFINITION - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) +#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER +#define EPICS_ATOMIC_READ_MEMORY_BARRIER +EPICS_ATOMIC_INLINE int epicsAtomicReadMemoryBarrier () { - return atomic_cas_uint ( pTarget, oldVal, newVal ); + membar_consumer (); } +#endif -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER +#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER +EPICS_ATOMIC_INLINE int epicsAtomicWriteMemoryBarrier () +{ + membar_producer (); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_INTT +#define EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ) +{ + STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) ); + return ( int ) atomic_cas_uint ( pTarget, ( unsigned ) oldVal, + ( unsigned ) newVal ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_SIZET +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapSizeT ( + size_t * pTarget, + size_t oldVal, size_t newVal ) +{ + STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); + void ** ppPtr = (void **) pTarget; + return ( size_t ) atomic_cas_ptr ( ppPtr, ( void * )oldVal, ( void * )newVal ); +} +#endif + +#ifndef EPICS_ATOMIC_CAS_PTRT +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( + EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldVal, + EpicsAtomicPtrT newVal ) { return atomic_cas_ptr ( pTarget, oldVal, newVal ); } +#endif -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +#ifndef EPICS_ATOMIC_INCR_INTT +#define EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) { - void * const pTarg = ( void * ) ( pTarget ); - return ( size_t ) atomic_inc_ptr_nv ( pTarg ); + STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return ( int ) atomic_inc_uint_nv ( pTarg ); } +#endif -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +#ifndef EPICS_ATOMIC_INCR_SIZET +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - void * const pTarg = ( void * ) ( pTarget ); - return atomic_dec_ptr_nv ( pTarg ); + STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); + void ** const ppTarg = ( void ** ) ( pTarget ); + return ( size_t ) atomic_inc_ptr_nv ( ppTarg ); } +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +#ifndef EPICS_ATOMIC_DECR_INTT +#define EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) { - *pTarget = newVal; - membar_producer(); + STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return ( int ) atomic_dec_uint_nv ( pTarg ); } +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +#ifndef EPICS_ATOMIC_DECR_SIZET +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - *pTarget = newVal; - membar_producer(); + STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); + void ** const pTarg = ( void ** ) ( pTarget ); + return ( size_t ) atomic_dec_ptr_nv ( pTarg ); } +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +#ifndef EPICS_ATOMIC_ADD_INTT +#define EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) { - *pTarget = newVal; - membar_producer(); + STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) ); + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return ( int ) atomic_add_int_nv ( pTarg, delta ); } +#endif -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +#ifndef EPICS_ATOMIC_ADD_SIZET +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, + size_t delta ) { - membar_consumer (); - return *pTarget; + STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); + void ** const pTarg = ( void ** ) ( pTarget ); + return ( size_t ) atomic_add_ptr_nv ( pTarg, ( ssize_t ) delta ); } +#endif -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +#ifndef EPICS_ATOMIC_SUB_SIZET +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, + size_t delta ) { - membar_consumer (); - return *pTarget; -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - membar_consumer (); - return *pTarget; + STATIC_ASSERT ( sizeof ( void * ) == sizeof ( size_t ) ); + void ** const pTarg = ( void ** ) ( pTarget ); + ssize_t = sdelta = ( ssize_t ) delta; + return ( size_t ) atomic_add_ptr_nv ( pTarg, -sdelta ); } +#endif #ifdef __cplusplus } /* end of extern "C" */ @@ -101,6 +158,9 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * p #endif /* ifdef __SunOS_5_10 */ -#endif /* if defined ( OSD_ATOMIC_INLINE ) */ +#include "epicsAtomicDefault.h" + +#endif /* if defined ( EPICS_ATOMIC_INLINE ) */ #endif /* epicsAtomicOSD_h */ + diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp new file mode 100644 index 000000000..b7f7b17c2 --- /dev/null +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp @@ -0,0 +1,22 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#define epicsExportSharedSymbols +#include "epicsAtomic.h" + +// if the compiler is unable to inline then instantiate out-of-line +#ifndef EPICS_ATOMIC_INLINE +#define EPICS_ATOMIC_INLINE +#include "epicsAtomic.h" +#endif + diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index b7a9e0f4b..c54a2b4c2 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -15,13 +15,11 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#if defined ( OSD_ATOMIC_INLINE ) +#if defined ( EPICS_ATOMIC_INLINE ) #include "vxWorks.h" /* obtain the version of vxWorks */ #include "epicsAssert.h" -#define OSD_ATOMIC_INLINE_DEFINITION - /* * With vxWorks 6.6 and later we need to use vxAtomicLib * to implement this functionality correctly on SMP systems @@ -35,6 +33,22 @@ extern "C" { #endif /* __cplusplus */ +#ifndef EPICS_READ_MEMORY_BARRIER +#define EPICS_READ_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsReadMemoryBarrier () +{ + VX_MEM_BARRIER_R (); +} +#endif + +#ifndef EPICS_WRITE_MEMORY_BARRIER +#define EPICS_WRITE_MEMORY_BARRIER +EPICS_ATOMIC_INLINE void epicsWriteMemoryBarrier () +{ + VX_MEM_BARRIER_W (); +} +#endif + /* * we make the probably correct guess that if ULONG_MAX * is the same as UINT_MAX then sizeof ( atomic_t ) @@ -48,127 +62,134 @@ extern "C" { #if ULONG_MAX == UINT_MAX STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) ); +STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( EpicsAtomicPtrT ) ); -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) + +#ifndef EPICS_ATOMIC_INCR_SIZET +#define EPICS_ATOMIC_INCR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + const atomic_t oldVal = vxAtomicInc ( pTarg ); + return 1 + ( size_t ) ( oldVal ); +} +#endif + +#ifndef EPICS_ATOMIC_DECR_SIZET +#define EPICS_ATOMIC_DECR_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + const atomic_t oldVal = vxAtomicDec ( pTarg ); + return ( ( size_t ) oldVal ) - 1u; +} +#endif + +#ifndef EPICS_ATOMIC_ADD_SIZET +#define EPICS_ATOMIC_ADD_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ) { /* - * vxAtomicLib doc indicates that vxAtomicInc is - * implemented using unsigned arithmetic + * vxAtomicLib doc indicates that vxAtomicAdd is + * implemented using signed arithmetic, but it + * does not change the end result because twos + * complement addition is used in either case */ atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - const atomic_t oldVal = vxAtomicInc ( pTarg ) + 1; - return ( ( size_t ) ( oldVal ) ) + 1u; -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) + const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta ); + return delta + ( size_t ) oldVal; +} #endif #ifndef EPICS_ATOMIC_SUB_SIZET +#define EPICS_ATOMIC_SUB_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ) { /* - * vxAtomicLib doc indicates that vxAtomicDec is - * implemented using unsigned arithmetic + * vxAtomicLib doc indicates that vxAtomicSub is + * implemented using signed arithmetic, but it + * does not change the end result because twos + * complement subtraction is used in either case */ atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - const atomic_t oldVal = vxAtomicDec ( pTarg ) - 1; - return ( ( size_t ) ( oldVal ) ) - 1u; + const atomic_t oldVal = vxAtomicSub ( pTarg, (atomic_t) delta ); + return ( ( size_t ) oldVal ) - delta; } +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +#ifndef EPICS_ATOMIC_CAS_SIZET +#define EPICS_ATOMIC_CAS_SIZET +EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, + size_t oldVal, size_t newVal ) { atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - vxAtomicSet ( pTarg, newVal ); + return ( size_t ) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); } +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - vxAtomicSet ( pTarg, newVal ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return ( size_t ) vxAtomicGet ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return ( EpicsAtomicPtrT ) vxAtomicGet ( pTarg ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, +#ifndef EPICS_ATOMIC_CAS_PTRT +#define EPICS_ATOMIC_CAS_PTRT +EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) { atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); return (EpicsAtomicPtrT) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); } +#endif #else /* ULONG_MAX == UINT_MAX */ /* - * if its 64 bit vxWorks and the compiler doesnt + * if its 64 bit SMP vxWorks and the compiler doesnt * have an intrinsic then maybe there isnt any way to * implement these without using a global lock because - * size_t is bigger than atomic_t + * size_t is maybe bigger than atomic_t + * + * I dont yet have access to vxWorks manuals for + * 64 bit systems so this is still undecided, but is + * defaulting now to a global lock */ -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) -{ - return epicsLockedIncrSizeT ( pTarget ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) -{ - return epicsLockedDecrSizeT ( pTarget ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - epicsLockedSetSizeT ( pTarget, newVal ); -} - -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - epicsLockedSetPtrT ( pTarget, newVal ); -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - return epicsLockedGetSizeT ( pTarget ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - return epicsLockedGetPtrT ( pTarget ); -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); -} #endif /* ULONG_MAX == UINT_MAX */ -STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); +STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( int ) ); -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +#ifndef EPICS_ATOMIC_INCR_INTT +#define EPICS_ATOMIC_INCR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ) { atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - vxAtomicSet ( pTarg, newVal ); + const atomic_t oldVal = vxAtomicInc ( pTarg ); + return 1 + ( int ) oldVal; } +#endif -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) -{ - STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); - atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return ( unsigned ) vxAtomicGet ( pTarg ); -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) +#ifndef EPICS_ATOMIC_DECR_INTT +#define EPICS_ATOMIC_DECR_INTT +EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget ) { atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); - return (unsigned) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); + const atomic_t oldVal = vxAtomicDec ( pTarg ); + return ( ( int ) oldVal ) - 1; } +#endif + +#ifndef EPICS_ATOMIC_ADD_INTT +#define EPICS_ATOMIC_ADD_INTT +EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta ); + return delta + ( int ) oldVal; +} +#endif + +#ifndef EPICS_ATOMIC_CAS_INTT +#define EPICS_ATOMIC_CAS_INTT +EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, + int oldVal, int newVal ) +{ + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return ( int ) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal ); +} +#endif #ifdef __cplusplus } /* end of extern "C" */ @@ -183,129 +204,39 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, extern "C" { #endif /* __cplusplus */ -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +#ifndef EPICS_ATOMIC_LOCK +#define EPICS_ATOMIC_LOCK + +typedef struct EpicsAtomicLockKey { int m_key; } EpicsAtomicLockKey; + +EPICS_ATOMIC_INLINE void epicsAtomicLock ( EpicsAtomicLockKey * pKey ) { -# ifdef __m68k__ - return ++(*pTarget); -# else - /* - * no need for memory barrior since this - * is a single cpu system. - */ - const int key = intLock (); - const size_t result = ++(*pTarget); - intUnlock ( key ); - return result; -# endif + pKey->m_key = intLock (); } -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +EPICS_ATOMIC_INLINE EpicsAtomicLockKey epicsAtomicUnlock ( EpicsAtomicLockKey * pKey ) { -# ifdef __m68k__ - return --(*pTarget); -# else - /* - * no need for memory barrior since this - * is a single cpu system - */ - const int key = intLock (); - const size_t result = --(*pTarget); - intUnlock ( key ); - return result; + intUnlock ( pKey->m_key ); +} #endif -} -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - *pTarget = newVal; -} +#ifndef EPICS_READ_MEMORY_BARRIER +#define EPICS_READ_MEMORY_BARRIER +/* + * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system + * (we are not protecting against multiple access to memory mapped IO) + */ +EPICS_ATOMIC_INLINE void epicsReadMemoryBarrier () {} +#endif -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - *pTarget = newVal; -} - -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - *pTarget = newVal; -} - -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - return *pTarget; -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - return *pTarget; -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - */ - return *pTarget; -} - -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - * - * !!!! beware, this will not guarantee an atomic operation - * !!!! if the target operand is on the VME bus - */ - const int key = intLock (); - const unsigned curr = *pTarget; - if ( curr == oldVal ) { - *pTarget = newVal; - } - intUnlock ( key ); - return curr; -} - -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) -{ - /* - * no need for memory barrior since this - * is a single cpu system - * - * !!!! beware, this will not guarantee an atomic operation - * !!!! if the target operand is on the VME bus - */ - const int key = intLock (); - const EpicsAtomicPtrT curr = *pTarget; - if ( curr == oldVal ) { - *pTarget = newVal; - } - intUnlock ( key ); - return curr; -} +#ifndef EPICS_WRITE_MEMORY_BARRIER +#define EPICS_WRITE_MEMORY_BARRIER +/* + * no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system + * (we are not protecting against multiple access to memory mapped IO) + */ +EPICS_ATOMIC_INLINE void epicsWriteMemoryBarrier () {} +#endif #ifdef __cplusplus } /* end of extern "C" */ @@ -313,6 +244,9 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * #endif /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */ -#endif /* if defined ( OSD_ATOMIC_INLINE ) */ +#include "epicsAtomicDefault.h" + +#endif /* if defined ( EPICS_ATOMIC_INLINE ) */ #endif /* epicsAtomicOSD_h */ + diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index 3c94f9850..02649e1ca 100644 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -109,8 +109,8 @@ testHarness_SRCS += epicsMutexTest.cpp TESTS += epicsMutexTest TESTPROD_HOST += epicsAtomicTest -epicsAtomicTest_SRCS += epicsAtomicTest.c -testHarness_SRCS += epicsAtomicTest.c +epicsAtomicTest_SRCS += epicsAtomicTest.cpp +testHarness_SRCS += epicsAtomicTest.cpp TESTS += epicsAtomicTest TESTPROD_HOST += epicsExceptionTest diff --git a/src/libCom/test/epicsAtomicPerform.cpp b/src/libCom/test/epicsAtomicPerform.cpp index 3a116008d..98b6e9939 100644 --- a/src/libCom/test/epicsAtomicPerform.cpp +++ b/src/libCom/test/epicsAtomicPerform.cpp @@ -1,6 +1,8 @@ #include +#include #include +#include #include "epicsInterrupt.h" #include "epicsAtomic.h" @@ -9,6 +11,8 @@ #include "testMain.h" using std :: size_t; +using namespace epics; +using namespace atomic; class RefCtr { public: @@ -214,234 +218,184 @@ inline void passRefOwnership1000 ( const Ownership & ownershipIn, Ownership & ow time_t extTime = 0; +template < class T > +class OrdinaryIncr { +public: + OrdinaryIncr () : m_target ( 0 ) {} + void run (); + void diagnostic ( double delay ); +private: + T m_target; +}; + // tests the time it takes to perform a call to an external // function and also increment an integer word. The // epicsInterruptIsInterruptContext function is an // out-of-line function implemented in a sharable library // so hopefully it wont be optimized away. -inline void tenOrdinaryIncr ( size_t & target ) +template < class T > +inline void OrdinaryIncr < T > :: run () { - int result = 0; - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - result += epicsInterruptIsInterruptContext (); - target = static_cast < unsigned > ( result ); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); + m_target += epicsInterruptIsInterruptContext (); } -inline void oneHundredOrdinaryIncr ( size_t & target ) +template < class T > +void OrdinaryIncr < T > :: diagnostic ( double delay ) { - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); - tenOrdinaryIncr ( target ); + delay /= 10.0; + delay *= 1e6; + const char * const pName = typeid ( T ) . name (); + testDiag ( "raw incr of \"%s\" and a NOOP function call takes %f microseconds", + pName, delay ); } -inline void oneThousandOrdinaryIncr ( size_t & target ) +template < class T > +class AtomicIncr { +public: + AtomicIncr () : m_target ( 0 ) {} + void run (); + void diagnostic ( double delay ); +private: + T m_target; +}; + +template < class T > +inline void AtomicIncr < T > :: run () { - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); - oneHundredOrdinaryIncr ( target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); + increment ( m_target ); } -inline void tenAtomicIncr ( size_t & target ) +template < class T > +void AtomicIncr < T > :: diagnostic ( double delay ) { - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); - epicsAtomicIncrSizeT ( & target ); + delay /= 10.0; + delay *= 1e6; + const char * const pName = typeid ( T ) . name (); + testDiag ( "epicsAtomicIncr \"%s\" takes %f microseconds", + pName, delay ); } -inline void oneHundredAtomicIncr ( size_t & target ) +template < class T > T trueValue (); +template < class T > T falseValue (); + +// int +template <> +inline int trueValue < int > () { return 1; } + +template <> +inline int falseValue < int > () { return 0; } + +// size_t +template <> +inline size_t trueValue < size_t > () { return 1u; } + +template <> +inline size_t falseValue < size_t > () { return 0u; } + +// EpicsAtomicPtrT +template <> +inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > () +{ static char c; return & c; } + +template <> +inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > () +{ return 0u; } + +template < class T > +class AtomicCmpAndSwap { +public: + AtomicCmpAndSwap () : m_target ( 0 ) {} + void run (); + void diagnostic ( double delay ); +private: + T m_target; +}; + +template < class T > +inline void AtomicCmpAndSwap < T > :: run () { - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); - tenAtomicIncr ( target ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); + compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () ); } -inline void oneThousandAtomicIncr ( size_t & target ) +template < class T > +void AtomicCmpAndSwap < T > :: diagnostic ( double delay ) { - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); - oneHundredAtomicIncr ( target ); + delay /= 10.0; + delay *= 1e6; + const char * const pName = typeid ( T ) . name (); + testDiag ( "epicsAtomicCmpAndSwap of \"%s\" takes %f microseconds", + pName, delay ); } -inline void tenAtomicCmpAndSwap ( unsigned & target ) +template < class T > +class AtomicSet { +public: + AtomicSet () : m_target ( 0 ) {} + void run (); + void diagnostic ( double delay ); +private: + T m_target; +}; + +template < class T > +inline void AtomicSet < T > :: run () { - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); - epicsAtomicCmpAndSwapUIntT ( & target, false, true ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); + set ( m_target, 0 ); } -inline void oneHundredAtomicCmpAndSwap ( unsigned & target ) +template < class T > +void AtomicSet < T > :: diagnostic ( double delay ) { - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); - tenAtomicCmpAndSwap ( target ); -} - -inline void oneThousandAtomicCmpAndSwap ( unsigned & target ) -{ - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); - oneHundredAtomicCmpAndSwap ( target ); -} - -inline void tenAtomicSet ( size_t & target ) -{ - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); - epicsAtomicSetSizeT ( & target, 0 ); -} - -inline void oneHundredAtomicSet ( size_t & target ) -{ - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); - tenAtomicSet ( target ); -} - -inline void oneThousandAtomicSet ( size_t & target ) -{ - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); - oneHundredAtomicSet ( target ); + delay /= 10.0; + delay *= 1e6; + const char * const pName = typeid ( T ) . name (); + testDiag ( "epicsAtomicSet of \"%s\" takes %f microseconds", + pName, delay ); } static const unsigned N = 10000; -void ordinaryIncrPerformance () -{ - epicsTime begin = epicsTime::getCurrent (); - size_t target; - epicsAtomicSetSizeT ( & target, 0 ); - for ( unsigned i = 0; i < N; i++ ) { - oneThousandOrdinaryIncr ( target ); - } - double delay = epicsTime::getCurrent () - begin; - testOk1 ( target == 0u ); - delay /= N * 1000u; // convert to delay per call - delay *= 1e6; // convert to micro seconds - testDiag ( "raw incr and a NOOP function call takes %f microseconds", delay ); -} - -void epicsAtomicIncrPerformance () -{ - epicsTime begin = epicsTime::getCurrent (); - size_t target; - epicsAtomicSetSizeT ( & target, 0 ); - for ( unsigned i = 0; i < N; i++ ) { - oneThousandAtomicIncr ( target ); - } - double delay = epicsTime::getCurrent () - begin; - testOk1 ( target == N * 1000u ); - delay /= N * 1000u; // convert to delay per call - delay *= 1e6; // convert to micro seconds - testDiag ( "epicsAtomicIncr() takes %f microseconds", delay ); -} - -void atomicCmpAndSwapPerformance () -{ - epicsTime begin = epicsTime::getCurrent (); - unsigned target; - epicsAtomicSetUIntT ( & target, 0 ); - testOk1 ( ! target ); - for ( unsigned i = 0; i < N; i++ ) { - oneThousandAtomicCmpAndSwap ( target ); - } - double delay = epicsTime::getCurrent () - begin; - testOk1 ( target ); - delay /= N * 1000u; // convert to delay per call - delay *= 1e6; // convert to micro seconds - testDiag ( "epicsAtomicCmpAndSwap() takes %f microseconds", delay ); -} - void recursiveOwnershipRetPerformance () { RefCtr refCtr; epicsTime begin = epicsTime::getCurrent (); - for ( unsigned i = 0; i < N; i++ ) { + for ( size_t i = 0; i < N; i++ ) { Ownership ownership ( refCtr ); recurRetOwner1000 ( ownership ); } @@ -455,7 +409,7 @@ void ownershipPassRefPerformance () { RefCtr refCtr; epicsTime begin = epicsTime::getCurrent (); - for ( unsigned i = 0; i < N; i++ ) { + for ( size_t i = 0; i < N; i++ ) { Ownership ownershipSrc ( refCtr ); Ownership ownershipDest; passRefOwnership1000 ( ownershipSrc, ownershipDest ); @@ -466,34 +420,87 @@ void ownershipPassRefPerformance () testDiag ( "passRefOwnership() takes %f microseconds", delay ); } -void epicsAtomicSetPerformance () +template < class T > +class Ten { - epicsTime begin = epicsTime::getCurrent (); - size_t target; - for ( unsigned i = 0; i < N; i++ ) { - oneThousandAtomicSet ( target ); - } - double delay = epicsTime::getCurrent () - begin; - testOk1 ( target == 0u ); - delay /= N * 1000u; // convert to delay per call - delay *= 1e6; // convert to micro seconds - testDiag ( "epicsAtomicSet() takes %f microseconds", delay ); +public: + void run (); + void diagnostic ( double delay ); + typedef Ten < Ten < T > > Hundred; + typedef Ten < Hundred > Thousand; +private: + T m_target; +}; + +template < class T > +inline void Ten < T > :: run () +{ + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); + m_target.run (); } -MAIN(epicsAtomicPerform) +template < class T > +void Ten < T > :: diagnostic ( double delay ) { - testPlan(5); + m_target.diagnostic ( delay / 10.0 ); +} + +template < class T > +void measurePerformance () +{ + epicsTime begin = epicsTime::getCurrent (); + T target; + for ( size_t i = 0; i < N; i++ ) { + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + target.run (); + } + double delay = epicsTime::getCurrent () - begin; + delay /= ( N * 10u ); // convert to delay per call + target.diagnostic ( delay ); +} + +template < class T > +void measure () +{ + measurePerformance < typename Ten < T > :: Hundred > (); +} + +MAIN ( epicsAtomicPerform ) +{ + testPlan ( 0 ); // // The tests running here are measuring fast // functions so they tend to be impacted // by where the cache lines are wrt to the - // virtual pages perhaps + // virtual pages perhap // - epicsAtomicSetPerformance (); - ordinaryIncrPerformance (); - epicsAtomicIncrPerformance (); + measure < AtomicSet < int > > (); + measure < AtomicSet < size_t > > (); + measure < AtomicSet < void * > > (); + measure < OrdinaryIncr < int > > (); + measure < OrdinaryIncr < size_t > > (); + measure < AtomicIncr < int > > (); + measure < AtomicIncr < size_t > > (); + measure < AtomicCmpAndSwap < int > > (); + measure < AtomicCmpAndSwap < size_t > > (); + measure < AtomicCmpAndSwap < void * > > (); recursiveOwnershipRetPerformance (); ownershipPassRefPerformance (); - atomicCmpAndSwapPerformance (); return testDone(); } diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c deleted file mode 100644 index 79f90f6d5..000000000 --- a/src/libCom/test/epicsAtomicTest.c +++ /dev/null @@ -1,175 +0,0 @@ - -#include -#include - -#include "epicsAtomic.h" -#include "epicsTime.h" -#include "epicsThread.h" -#include "epicsUnitTest.h" -#include "testMain.h" - -typedef struct TestDataIncrDecr { - size_t m_testValue; - size_t m_testIterations; -} TestDataIncrDecr; - -static void incr ( void *arg ) -{ - TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg; - epicsAtomicIncrSizeT ( & pTestData->m_testValue ); - epicsAtomicIncrSizeT ( & pTestData->m_testIterations ); -} - -static void decr ( void *arg ) -{ - TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg; - epicsAtomicDecrSizeT ( & pTestData->m_testValue ); - epicsAtomicIncrSizeT ( & pTestData->m_testIterations ); -} - -typedef struct TestDataTNS_UIntT { - unsigned m_testValue; - size_t m_testIterationsSet; - size_t m_testIterationsNotSet; -} TestDataTNS_UIntT; - -typedef struct TestDataTNS_PtrT { - EpicsAtomicPtrT m_testValue; - size_t m_testIterationsSet; - size_t m_testIterationsNotSet; -} TestDataTNS_PtrT; - - -int isModulo ( size_t N, size_t n ) -{ - return ( n % N ) == 0u; -} - -static void tns_UIntT ( void *arg ) -{ - TestDataTNS_UIntT * const pTestData = (TestDataTNS_UIntT *) arg; - /* - * intentionally waste cpu and maximize - * contention for the shared data - */ - epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); - while ( ! epicsAtomicCmpAndSwapUIntT ( & pTestData->m_testValue, 0u, 1u ) ) { - } - epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); - epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u ); - epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); -} - -static void tns_PtrT ( void *arg ) -{ - static char dummy = 0; - TestDataTNS_PtrT * const pTestData = (TestDataTNS_PtrT *) arg; - /* - * intentionally waste cpu and maximize - * contention for the shared data - */ - epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); - while ( ! epicsAtomicCmpAndSwapPtrT ( & pTestData->m_testValue, 0, & dummy ) ) { - } - epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); - epicsAtomicSetPtrT ( & pTestData->m_testValue, 0u ); - epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); -} - -MAIN(osiAtomicTest) -{ - const unsigned int stackSize = - epicsThreadGetStackSize ( epicsThreadStackSmall ); - - testPlan(14); - - { - static const size_t N = 100; - size_t i; - TestDataIncrDecr testData = { 0, N };; - epicsAtomicSetSizeT ( & testData.m_testValue, N ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, - "set/get %u", testData.m_testValue ); - epicsAtomicSetSizeT ( & testData.m_testIterations, 0u ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 0u, - "set/get %u", testData.m_testIterations ); - for ( i = 0u; i < N; i++ ) { - epicsThreadCreate ( "incr", - 50, stackSize, incr, & testData ); - epicsThreadCreate ( "decr", - 50, stackSize, decr, & testData ); - } - while ( testData.m_testIterations < 2 * N ) { - epicsThreadSleep ( 0.01 ); - } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N, - "incr/decr iterations %u", - testData.m_testIterations ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, - "incr/decr final value %u", - testData.m_testValue ); - } - - { - static const unsigned initVal = 1; - static const size_t N = 10; - size_t i; - TestDataTNS_UIntT testData = { 0, N, N }; - epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, - "set/get %u", testData.m_testIterationsSet ); - epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "set/get %u", testData.m_testIterationsNotSet ); - epicsAtomicSetUIntT ( & testData.m_testValue, initVal ); - testOk ( epicsAtomicGetUIntT ( & testData.m_testValue ) == initVal, - "PtrT set/get %u", testData.m_testValue ); - for ( i = 0u; i < N; i++ ) { - epicsThreadCreate ( "tns", - 50, stackSize, tns_UIntT, & testData ); - } - epicsAtomicSetUIntT ( & testData.m_testValue, 0u ); - while ( testData.m_testIterationsSet < N ) { - epicsThreadSleep ( 0.01 ); - } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, - "test and set iterations %u", - testData.m_testIterationsSet ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "test and set not-set tracking = %u", - testData.m_testIterationsNotSet ); - } - - { - static const size_t N = 10; - static char dummy; - size_t i; - TestDataTNS_PtrT testData = { 0, N, N }; - epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u, - "set/get %u", testData.m_testIterationsSet ); - epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "SizeT set/get %u", testData.m_testIterationsNotSet ); - epicsAtomicSetPtrT ( & testData.m_testValue, & dummy ); - testOk ( epicsAtomicGetPtrT ( & testData.m_testValue ) == & dummy, - "PtrT set/get %p", testData.m_testValue ); - for ( i = 0u; i < N; i++ ) { - epicsThreadCreate ( "tns", - 50, stackSize, tns_PtrT, & testData ); - } - epicsAtomicSetPtrT ( & testData.m_testValue, 0u ); - while ( testData.m_testIterationsSet < N ) { - epicsThreadSleep ( 0.01 ); - } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, - "test and set iterations %u", - testData.m_testIterationsSet ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "test and set not-set tracking = %u", - testData.m_testIterationsNotSet ); - } - - return testDone(); -} - diff --git a/src/libCom/test/epicsAtomicTest.cpp b/src/libCom/test/epicsAtomicTest.cpp new file mode 100644 index 000000000..ff92a28fa --- /dev/null +++ b/src/libCom/test/epicsAtomicTest.cpp @@ -0,0 +1,238 @@ + +#include +#include + +#include "epicsAtomic.h" +#include "epicsTime.h" +#include "epicsThread.h" +#include "epicsUnitTest.h" +#include "testMain.h" + +using namespace epics; +using namespace atomic; + +template < class T > +struct TestDataIncrDecr { + T m_testValue; + size_t m_testIterations; +}; + +template < class T > +struct TestDataAddSub { + T m_testValue; + size_t m_testIterations; + static const T delta = 17; +}; + +template < class T > +static void incr ( void *arg ) +{ + TestDataIncrDecr < T > * const pTestData = + reinterpret_cast < TestDataIncrDecr < T > * > ( arg ); + increment ( pTestData->m_testValue ); + increment ( pTestData->m_testIterations ); +} + +template < class T > +static void decr ( void *arg ) +{ + TestDataIncrDecr < T > * const pTestData = + reinterpret_cast < TestDataIncrDecr < T > * > ( arg ); + decrement ( pTestData->m_testValue ); + increment ( pTestData->m_testIterations ); +} + + +template < class T > +static void add ( void *arg ) +{ + TestDataAddSub < T > * const pTestData = + reinterpret_cast < TestDataAddSub < T > * > ( arg ); + add ( pTestData->m_testValue, TestDataAddSub < T > :: delta ); + increment ( pTestData->m_testIterations ); +} + +template < class T > +static void sub ( void *arg ) +{ + TestDataAddSub < T > * const pTestData = + reinterpret_cast < TestDataAddSub < T > * > ( arg ); + subtract ( pTestData->m_testValue, TestDataAddSub < T > :: delta ); + increment ( pTestData->m_testIterations ); +} + +template < class T > +struct TestDataCAS { + T m_testValue; + size_t m_testIterationsSet; + size_t m_testIterationsNotSet; +}; + +int isModulo ( size_t N, size_t n ) +{ + return ( n % N ) == 0u; +} + +template < class T > +static T trueValue (); +template < class T > +static T falseValue (); + +// int +template <> +inline int trueValue < int > () { return 1; } + +template <> +inline int falseValue < int > () { return 0; } + +// size_t +template <> +inline size_t trueValue < size_t > () { return 1u; } + +template <> +inline size_t falseValue < size_t > () { return 0u; } + +// EpicsAtomicPtrT +template <> +inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > () +{ static char c; return & c; } + +template <> +inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > () +{ return 0u; } + +template < class T > +static void cas ( void *arg ) +{ + TestDataCAS < T > * const pTestData = + reinterpret_cast < TestDataCAS < T > * > ( arg ); + /* + * intentionally waste cpu and maximize + * contention for the shared data + */ + increment ( pTestData->m_testIterationsNotSet ); + while ( ! compareAndSwap ( pTestData->m_testValue, + falseValue < T > (), + trueValue < T > () ) ) { + } + decrement ( pTestData->m_testIterationsNotSet ); + set ( pTestData->m_testValue, falseValue < T > () ); + increment ( pTestData->m_testIterationsSet ); +} + +template < class T > +void testIncrDecr () +{ + static const size_t N = 100; + static const T NT = static_cast < T > ( N ); + + const unsigned int stackSize = + epicsThreadGetStackSize ( epicsThreadStackSmall ); + + TestDataIncrDecr < T > testData = { 0, N }; + set ( testData.m_testValue, NT ); + testOk ( get ( testData.m_testValue ) == NT, + "set/get %u", testData.m_testValue ); + set ( testData.m_testIterations, 0u ); + testOk ( get ( testData.m_testIterations ) == 0u, + "set/get %u", testData.m_testIterations ); + for ( size_t i = 0u; i < N; i++ ) { + epicsThreadCreate ( "incr", + 50, stackSize, incr < T >, & testData ); + epicsThreadCreate ( "decr", + 50, stackSize, decr < T >, & testData ); + } + while ( testData.m_testIterations < 2 * N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( get ( testData.m_testIterations ) == 2 * N, + "incr/decr iterations %u", + testData.m_testIterations ); + testOk ( get ( testData.m_testValue ) == NT, + "incr/decr final value %u", + testData.m_testValue ); +} + +template < class T > +void testAddSub () +{ + static const size_t N = 100; + static const T NDT = TestDataAddSub < T > :: delta * + static_cast < T > ( N ); + + const unsigned int stackSize = + epicsThreadGetStackSize ( epicsThreadStackSmall ); + + TestDataIncrDecr < T > testData = { 0, N }; + set ( testData.m_testValue, NDT ); + testOk ( get ( testData.m_testValue ) == NDT, + "set/get %u", testData.m_testValue ); + set ( testData.m_testIterations, 0u ); + testOk ( get ( testData.m_testIterations ) == 0u, + "set/get %u", testData.m_testIterations ); + for ( size_t i = 0u; i < N; i++ ) { + epicsThreadCreate ( "add", + 50, stackSize, add < T >, & testData ); + epicsThreadCreate ( "sub", + 50, stackSize, sub < T >, & testData ); + } + while ( testData.m_testIterations < 2 * N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( get ( testData.m_testIterations ) == 2 * N, + "add/sub iterations %u", + testData.m_testIterations ); + testOk ( get ( testData.m_testValue ) == NDT, + "add/sub final value %u", + testData.m_testValue ); +} + +template < class T > +void testCAS () +{ + static const size_t N = 10; + + const unsigned int stackSize = + epicsThreadGetStackSize ( epicsThreadStackSmall ); + + TestDataCAS < T > testData = { 0, N, N }; + set ( testData.m_testIterationsSet, 0 ); + testOk ( get ( testData.m_testIterationsSet ) == 0u, + "set/get %u", testData.m_testIterationsSet ); + set ( testData.m_testIterationsNotSet, 0 ); + testOk ( get ( testData.m_testIterationsNotSet ) == 0u, + "set/get %u", testData.m_testIterationsNotSet ); + set ( testData.m_testValue, trueValue < T > () ); + testOk ( get ( testData.m_testValue ) == trueValue < T > (), + "set/get a true value" ); + for ( size_t i = 0u; i < N; i++ ) { + epicsThreadCreate ( "tns", + 50, stackSize, cas < T >, & testData ); + } + set ( testData.m_testValue, falseValue < T > () ); + while ( testData.m_testIterationsSet < N ) { + epicsThreadSleep ( 0.01 ); + } + testOk ( get ( testData.m_testIterationsSet ) == N, + "test and set iterations %u", + testData.m_testIterationsSet ); + testOk ( get ( testData.m_testIterationsNotSet ) == 0u, + "test and set not-set tracking = %u", + testData.m_testIterationsNotSet ); +} + +MAIN ( osiAtomicTest ) +{ + + testPlan ( 31 ); + + testIncrDecr < int > (); + testIncrDecr < size_t > (); + testAddSub < int > (); + testAddSub < size_t > (); + testCAS < int > (); + testCAS < size_t > (); + testCAS < EpicsAtomicPtrT > (); + + return testDone (); +}