o changed to more generic implementation to reduce the code size
o changed name, OSD_ATOMIC_INLINE to EPICS_ATOMIC_INLINE o changed supported data types, unsigned removed and int added (per reveiw at codeathon) o added add/subtract functions (per reveiw at codeathon) o now presuming that __sync_synchronize available all gcc 4 mingw does not provide windows mem barrier) o consolodated on one implemention for Microsoft invarient of cmplr intrinisic or win32 by using macros to config a shared header file o improved doc in epicsAtomic.h o added overloaded c++ interface in namespace epics :: atomic to epicsAtomic.h o added epicsAtomicReadMemoryBarrier and epicsAtomicWriteMemoryBarrier interface to epicsAtomic.h o changed the implementation so that each of the functions can be individually specified for a particular compiler, os, or in the generic implementation (this is accomplished with macros) o modified the functional and performance test so that they are based on templates so we can easily support new data types o modified performance tests to repeat function calls and measure performance using a template
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -26,178 +26,99 @@
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
#pragma intrinsic ( _InterlockedExchange )
|
||||
#pragma intrinsic ( _InterlockedCompareExchange )
|
||||
#pragma intrinsic ( _InterlockedIncrement )
|
||||
#pragma intrinsic ( _InterlockedDecrement )
|
||||
#pragma intrinsic ( _InterlockedExchange )
|
||||
#pragma intrinsic ( _InterlockedExchangeAdd )
|
||||
#if OSD_ATOMIC_64
|
||||
# pragma intrinsic ( _InterlockedIncrement64 )
|
||||
# pragma intrinsic ( _InterlockedDecrement64 )
|
||||
# pragma intrinsic ( _InterlockedExchange64 )
|
||||
# pragma intrinsic ( _InterlockedExchangeAdd64 )
|
||||
#endif
|
||||
|
||||
#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 */
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 */
|
||||
|
||||
235
src/libCom/osi/epicsAtomicDefault.h
Normal file
235
src/libCom/osi/epicsAtomicDefault.h
Normal file
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
222
src/libCom/osi/os/WIN32/epicsAtomicMS.h
Normal file
222
src/libCom/osi/os/WIN32/epicsAtomicMS.h
Normal file
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,149 +12,38 @@
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
|
||||
#ifndef epicsAtomicOSD_h
|
||||
#define epicsAtomicOSD_h
|
||||
|
||||
#if defined ( OSD_ATOMIC_INLINE )
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "epicsAssert.h"
|
||||
|
||||
#define STRICT
|
||||
#define VC_EXTRALEAN
|
||||
#include <windows.h>
|
||||
#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 */
|
||||
|
||||
@@ -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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#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 )
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 <limits.h>
|
||||
#include <atomic.h>
|
||||
|
||||
#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */
|
||||
#include <stdint.h>
|
||||
|
||||
#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 */
|
||||
|
||||
|
||||
22
src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp
Normal file
22
src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp
Normal file
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <typeinfo>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "epicsAtomic.h"
|
||||
#include "epicsTime.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
|
||||
typedef struct TestDataIncrDecr {
|
||||
size_t m_testValue;
|
||||
size_t m_testIterations;
|
||||
} TestDataIncrDecr;
|
||||
|
||||
static void incr ( void *arg )
|
||||
{
|
||||
TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg;
|
||||
epicsAtomicIncrSizeT ( & pTestData->m_testValue );
|
||||
epicsAtomicIncrSizeT ( & pTestData->m_testIterations );
|
||||
}
|
||||
|
||||
static void decr ( void *arg )
|
||||
{
|
||||
TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg;
|
||||
epicsAtomicDecrSizeT ( & pTestData->m_testValue );
|
||||
epicsAtomicIncrSizeT ( & pTestData->m_testIterations );
|
||||
}
|
||||
|
||||
typedef struct TestDataTNS_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();
|
||||
}
|
||||
|
||||
238
src/libCom/test/epicsAtomicTest.cpp
Normal file
238
src/libCom/test/epicsAtomicTest.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "epicsAtomic.h"
|
||||
#include "epicsTime.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
|
||||
using namespace epics;
|
||||
using namespace atomic;
|
||||
|
||||
template < class T >
|
||||
struct TestDataIncrDecr {
|
||||
T m_testValue;
|
||||
size_t m_testIterations;
|
||||
};
|
||||
|
||||
template < class T >
|
||||
struct TestDataAddSub {
|
||||
T m_testValue;
|
||||
size_t m_testIterations;
|
||||
static const T delta = 17;
|
||||
};
|
||||
|
||||
template < class T >
|
||||
static void incr ( void *arg )
|
||||
{
|
||||
TestDataIncrDecr < T > * const pTestData =
|
||||
reinterpret_cast < TestDataIncrDecr < T > * > ( arg );
|
||||
increment ( pTestData->m_testValue );
|
||||
increment ( pTestData->m_testIterations );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
static void decr ( void *arg )
|
||||
{
|
||||
TestDataIncrDecr < T > * const pTestData =
|
||||
reinterpret_cast < TestDataIncrDecr < T > * > ( arg );
|
||||
decrement ( pTestData->m_testValue );
|
||||
increment ( pTestData->m_testIterations );
|
||||
}
|
||||
|
||||
|
||||
template < class T >
|
||||
static void add ( void *arg )
|
||||
{
|
||||
TestDataAddSub < T > * const pTestData =
|
||||
reinterpret_cast < TestDataAddSub < T > * > ( arg );
|
||||
add ( pTestData->m_testValue, TestDataAddSub < T > :: delta );
|
||||
increment ( pTestData->m_testIterations );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
static void sub ( void *arg )
|
||||
{
|
||||
TestDataAddSub < T > * const pTestData =
|
||||
reinterpret_cast < TestDataAddSub < T > * > ( arg );
|
||||
subtract ( pTestData->m_testValue, TestDataAddSub < T > :: delta );
|
||||
increment ( pTestData->m_testIterations );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
struct TestDataCAS {
|
||||
T m_testValue;
|
||||
size_t m_testIterationsSet;
|
||||
size_t m_testIterationsNotSet;
|
||||
};
|
||||
|
||||
int isModulo ( size_t N, size_t n )
|
||||
{
|
||||
return ( n % N ) == 0u;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
static T trueValue ();
|
||||
template < class T >
|
||||
static T falseValue ();
|
||||
|
||||
// int
|
||||
template <>
|
||||
inline int trueValue < int > () { return 1; }
|
||||
|
||||
template <>
|
||||
inline int falseValue < int > () { return 0; }
|
||||
|
||||
// size_t
|
||||
template <>
|
||||
inline size_t trueValue < size_t > () { return 1u; }
|
||||
|
||||
template <>
|
||||
inline size_t falseValue < size_t > () { return 0u; }
|
||||
|
||||
// EpicsAtomicPtrT
|
||||
template <>
|
||||
inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > ()
|
||||
{ static char c; return & c; }
|
||||
|
||||
template <>
|
||||
inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > ()
|
||||
{ return 0u; }
|
||||
|
||||
template < class T >
|
||||
static void cas ( void *arg )
|
||||
{
|
||||
TestDataCAS < T > * const pTestData =
|
||||
reinterpret_cast < TestDataCAS < T > * > ( arg );
|
||||
/*
|
||||
* intentionally waste cpu and maximize
|
||||
* contention for the shared data
|
||||
*/
|
||||
increment ( pTestData->m_testIterationsNotSet );
|
||||
while ( ! compareAndSwap ( pTestData->m_testValue,
|
||||
falseValue < T > (),
|
||||
trueValue < T > () ) ) {
|
||||
}
|
||||
decrement ( pTestData->m_testIterationsNotSet );
|
||||
set ( pTestData->m_testValue, falseValue < T > () );
|
||||
increment ( pTestData->m_testIterationsSet );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
void testIncrDecr ()
|
||||
{
|
||||
static const size_t N = 100;
|
||||
static const T NT = static_cast < T > ( N );
|
||||
|
||||
const unsigned int stackSize =
|
||||
epicsThreadGetStackSize ( epicsThreadStackSmall );
|
||||
|
||||
TestDataIncrDecr < T > testData = { 0, N };
|
||||
set ( testData.m_testValue, NT );
|
||||
testOk ( get ( testData.m_testValue ) == NT,
|
||||
"set/get %u", testData.m_testValue );
|
||||
set ( testData.m_testIterations, 0u );
|
||||
testOk ( get ( testData.m_testIterations ) == 0u,
|
||||
"set/get %u", testData.m_testIterations );
|
||||
for ( size_t i = 0u; i < N; i++ ) {
|
||||
epicsThreadCreate ( "incr",
|
||||
50, stackSize, incr < T >, & testData );
|
||||
epicsThreadCreate ( "decr",
|
||||
50, stackSize, decr < T >, & testData );
|
||||
}
|
||||
while ( testData.m_testIterations < 2 * N ) {
|
||||
epicsThreadSleep ( 0.01 );
|
||||
}
|
||||
testOk ( get ( testData.m_testIterations ) == 2 * N,
|
||||
"incr/decr iterations %u",
|
||||
testData.m_testIterations );
|
||||
testOk ( get ( testData.m_testValue ) == NT,
|
||||
"incr/decr final value %u",
|
||||
testData.m_testValue );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
void testAddSub ()
|
||||
{
|
||||
static const size_t N = 100;
|
||||
static const T NDT = TestDataAddSub < T > :: delta *
|
||||
static_cast < T > ( N );
|
||||
|
||||
const unsigned int stackSize =
|
||||
epicsThreadGetStackSize ( epicsThreadStackSmall );
|
||||
|
||||
TestDataIncrDecr < T > testData = { 0, N };
|
||||
set ( testData.m_testValue, NDT );
|
||||
testOk ( get ( testData.m_testValue ) == NDT,
|
||||
"set/get %u", testData.m_testValue );
|
||||
set ( testData.m_testIterations, 0u );
|
||||
testOk ( get ( testData.m_testIterations ) == 0u,
|
||||
"set/get %u", testData.m_testIterations );
|
||||
for ( size_t i = 0u; i < N; i++ ) {
|
||||
epicsThreadCreate ( "add",
|
||||
50, stackSize, add < T >, & testData );
|
||||
epicsThreadCreate ( "sub",
|
||||
50, stackSize, sub < T >, & testData );
|
||||
}
|
||||
while ( testData.m_testIterations < 2 * N ) {
|
||||
epicsThreadSleep ( 0.01 );
|
||||
}
|
||||
testOk ( get ( testData.m_testIterations ) == 2 * N,
|
||||
"add/sub iterations %u",
|
||||
testData.m_testIterations );
|
||||
testOk ( get ( testData.m_testValue ) == NDT,
|
||||
"add/sub final value %u",
|
||||
testData.m_testValue );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
void testCAS ()
|
||||
{
|
||||
static const size_t N = 10;
|
||||
|
||||
const unsigned int stackSize =
|
||||
epicsThreadGetStackSize ( epicsThreadStackSmall );
|
||||
|
||||
TestDataCAS < T > testData = { 0, N, N };
|
||||
set ( testData.m_testIterationsSet, 0 );
|
||||
testOk ( get ( testData.m_testIterationsSet ) == 0u,
|
||||
"set/get %u", testData.m_testIterationsSet );
|
||||
set ( testData.m_testIterationsNotSet, 0 );
|
||||
testOk ( get ( testData.m_testIterationsNotSet ) == 0u,
|
||||
"set/get %u", testData.m_testIterationsNotSet );
|
||||
set ( testData.m_testValue, trueValue < T > () );
|
||||
testOk ( get ( testData.m_testValue ) == trueValue < T > (),
|
||||
"set/get a true value" );
|
||||
for ( size_t i = 0u; i < N; i++ ) {
|
||||
epicsThreadCreate ( "tns",
|
||||
50, stackSize, cas < T >, & testData );
|
||||
}
|
||||
set ( testData.m_testValue, falseValue < T > () );
|
||||
while ( testData.m_testIterationsSet < N ) {
|
||||
epicsThreadSleep ( 0.01 );
|
||||
}
|
||||
testOk ( get ( testData.m_testIterationsSet ) == N,
|
||||
"test and set iterations %u",
|
||||
testData.m_testIterationsSet );
|
||||
testOk ( get ( testData.m_testIterationsNotSet ) == 0u,
|
||||
"test and set not-set tracking = %u",
|
||||
testData.m_testIterationsNotSet );
|
||||
}
|
||||
|
||||
MAIN ( osiAtomicTest )
|
||||
{
|
||||
|
||||
testPlan ( 31 );
|
||||
|
||||
testIncrDecr < int > ();
|
||||
testIncrDecr < size_t > ();
|
||||
testAddSub < int > ();
|
||||
testAddSub < size_t > ();
|
||||
testCAS < int > ();
|
||||
testCAS < size_t > ();
|
||||
testCAS < EpicsAtomicPtrT > ();
|
||||
|
||||
return testDone ();
|
||||
}
|
||||
Reference in New Issue
Block a user