o no longer need to define OSD_ATOMIC_GCC
o removed function epicsAtomicTestAndSetUIntT o added new functions epicsAtomicSetPtrT epicsAtomicGetPtrT epicsAtomicCmpAndSwapUIntT epicsAtomicCmpAndSwapPtrT o changed msvc intrinsics to define memory fence o fixed mutex synchronized version so that its slow, but correct if the c++ compiler doesnt synchronized local scope static initialization o changed most of the set/get methods to use memory barriers instead of some other primitive o added additional tests
This commit is contained in:
committed by
Andrew Johnson
parent
c872c44668
commit
bd1b1479f4
@@ -39,16 +39,17 @@
|
||||
( defined ( __i486 ) || defined ( __pentium ) || \
|
||||
defined ( __pentiumpro ) || defined ( __MMX__ ) )
|
||||
|
||||
#define GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER \
|
||||
( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 )
|
||||
|
||||
#define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \
|
||||
( GCC_ATOMIC_INTRINSICS_MIN_X86 && \
|
||||
( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 ) )
|
||||
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_GCC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -77,6 +78,13 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget,
|
||||
__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 )
|
||||
{
|
||||
__sync_synchronize ();
|
||||
@@ -89,10 +97,22 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget )
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget )
|
||||
{
|
||||
const size_t prev = __sync_lock_test_and_set ( pTarget, 1u );
|
||||
return prev == 0;
|
||||
__sync_synchronize ();
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget,
|
||||
unsigned oldVal, unsigned newVal )
|
||||
{
|
||||
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -101,6 +121,11 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
|
||||
#else /* if GCC_ATOMIC_INTRINSICS_AVAIL */
|
||||
|
||||
# if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER && __i386
|
||||
/* 386 hardware is probably rare today even in embedded systems */
|
||||
# warning "this code will run much faster if specifying i486 or better"
|
||||
# endif
|
||||
|
||||
/*
|
||||
* not available as gcc intrinsics so we
|
||||
* will employ an os specific inline solution
|
||||
|
||||
@@ -24,21 +24,6 @@
|
||||
|
||||
#ifdef _MSC_EXTENSIONS
|
||||
|
||||
/*
|
||||
* I have discovered an anomaly in visual c++ where
|
||||
* the DLL instantiation of an exported inline interface
|
||||
* does not occur in a c++ code unless "inline" is used.
|
||||
*/
|
||||
#if defined ( __cplusplus )
|
||||
# define OSD_ATOMIC_INLINE inline
|
||||
#elif defined ( _MSC_VER )
|
||||
# define OSD_ATOMIC_INLINE __inline
|
||||
#endif
|
||||
|
||||
#if defined ( _M_X64 ) || defined ( _M_IA64 )
|
||||
# define OSD_ATOMIC_64
|
||||
#endif /* defined ( _M_X64 ) || defined ( _M_IA64 ) */
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
#pragma intrinsic ( _InterlockedExchange )
|
||||
@@ -54,6 +39,33 @@
|
||||
# pragma intrinsic ( _InterlockedExchangeAdd64 )
|
||||
#endif
|
||||
|
||||
#if _MSC_VER >= 1200
|
||||
# define OSD_ATOMIC_INLINE __forceinline
|
||||
#else
|
||||
# define OSD_ATOMIC_INLINE __inline
|
||||
#endif
|
||||
|
||||
#if defined ( _M_IX86 )
|
||||
# pragma warning( push )
|
||||
# pragma warning( disable : 4793 )
|
||||
OSD_ATOMIC_INLINE void OSD_ATOMIC_SYNC ()
|
||||
{
|
||||
long fence;
|
||||
__asm { xchg fence, eax }
|
||||
}
|
||||
# pragma warning( pop )
|
||||
#elif defined ( _M_X64 )
|
||||
# define OSD_ATOMIC_64
|
||||
# pragma intrinsic ( __faststorefence )
|
||||
# define OSD_ATOMIC_SYNC __faststorefence
|
||||
#elif defined ( _M_IA64 )
|
||||
# define OSD_ATOMIC_64
|
||||
# pragma intrinsic ( __mf )
|
||||
# define OSD_ATOMIC_SYNC __mf
|
||||
#else
|
||||
# error unexpected target architecture, msvc version of epicsAtomicCD.h
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The windows doc appears to recommend defining InterlockedExchange
|
||||
* to be _InterlockedExchange to cause it to be an intrinsic, but that
|
||||
@@ -71,27 +83,53 @@ STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) );
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
|
||||
{
|
||||
long * const pTarg = ( long * ) ( pTarget );
|
||||
_InterlockedExchange ( pTarg, ( long ) newVal );
|
||||
*pTarget = newVal;
|
||||
OSD_ATOMIC_SYNC ();
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
{
|
||||
*pTarget = newVal;
|
||||
OSD_ATOMIC_SYNC ();
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT newVal )
|
||||
{
|
||||
*pTarget = newVal;
|
||||
OSD_ATOMIC_SYNC ();
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget )
|
||||
{
|
||||
long * const pTarg = ( long * ) ( pTarget );
|
||||
return _InterlockedExchangeAdd ( pTarg, 0 );
|
||||
OSD_ATOMIC_SYNC ();
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * 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 _InterlockedCompareExchange ( pTarg, 1, 0 ) == 0;
|
||||
return (unsigned) _InterlockedCompareExchange ( pTarg,
|
||||
(long) newVal, (long) oldVal );
|
||||
}
|
||||
|
||||
|
||||
#if ! OSD_ATOMIC_64
|
||||
|
||||
/*
|
||||
* necessary for next four functions
|
||||
* 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
|
||||
@@ -110,22 +148,18 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
return _InterlockedDecrement ( pTarg );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
long * const pTarg = ( long * ) ( pTarget );
|
||||
_InterlockedExchange ( pTarg, ( long ) newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
long * const pTarg = ( long * ) ( pTarget );
|
||||
return _InterlockedExchangeAdd ( pTarg, 0 );
|
||||
return (EpicsAtomicPtrT) _InterlockedCompareExchange ( pTarg,
|
||||
(long) newVal, (long) oldVal );
|
||||
}
|
||||
|
||||
#else /* ! OSD_ATOMIC_64 */
|
||||
|
||||
/*
|
||||
* necessary for next four functions
|
||||
* necessary for next five functions
|
||||
*/
|
||||
STATIC_ASSERT ( sizeof ( long long ) == sizeof ( size_t ) );
|
||||
|
||||
@@ -141,16 +175,12 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
return _InterlockedDecrement64 ( pTarg );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
long long * const pTarg = ( long long * ) ( pTarget );
|
||||
_InterlockedExchange64 ( pTarg, ( long long ) newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
long long * const pTarg = ( long long * ) ( pTarget );
|
||||
return _InterlockedExchangeAdd64 ( pTarg, 0 );
|
||||
long long * const pTarg = ( longlong * ) ( pTarget );
|
||||
return (EpicsAtomicPtrT) _InterlockedCompareExchange64 ( pTarg,
|
||||
(long long) newVal, (long long) oldVal );
|
||||
}
|
||||
|
||||
#endif /* ! OSD_ATOMIC_64 */
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void * EpicsAtomicPtrT;
|
||||
|
||||
/*
|
||||
* lock out other smp processors from accessing the target,
|
||||
* sync target in cache, add one to target, flush target in
|
||||
@@ -53,26 +55,31 @@ epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget );
|
||||
*/
|
||||
epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue );
|
||||
epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue );
|
||||
epicsShareFunc void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue );
|
||||
|
||||
/*
|
||||
* fetch target in cache, return new value of target
|
||||
*/
|
||||
epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget );
|
||||
epicsShareFunc unsigned epicsAtomicGetUIntT ( const unsigned * pTarget );
|
||||
epicsShareFunc EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget );
|
||||
|
||||
/*
|
||||
* lock out other smp processors from accessing the target,
|
||||
* sync target in cache, if target is zero set target to
|
||||
* non-zero (true) value, flush target in cache, allow out
|
||||
* other smp processors to access the target, return true if
|
||||
* this request changed the target from a zero value to a
|
||||
* non-zero (true) value and otherwise false
|
||||
* sync target in cache, if target is equal to oldVal set target
|
||||
* to newVal, flush target in cache, allow other smp processors
|
||||
* to access the target, return the original value stored in the
|
||||
* target
|
||||
*
|
||||
* test and set is chosen as the primitive here because,
|
||||
* compared to comapare-and-swap it is more likely to
|
||||
* be implemented atomically on old architectures such as 68k
|
||||
* !!!! 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 epicsAtomicTestAndSetUIntT ( unsigned * pTarget );
|
||||
epicsShareFunc unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget,
|
||||
unsigned oldVal, unsigned newVal );
|
||||
epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal );
|
||||
|
||||
|
||||
/*
|
||||
* the following are, never inline and always synchronized by a global
|
||||
@@ -84,9 +91,14 @@ epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget );
|
||||
epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget );
|
||||
epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal );
|
||||
epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal );
|
||||
epicsShareFunc void epicsLockedSetPtrT ( unsigned * pTarget, EpicsAtomicPtrT newVal );
|
||||
epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget );
|
||||
epicsShareFunc unsigned epicsLockedGetUIntT ( const unsigned * pTarget );
|
||||
epicsShareFunc unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget );
|
||||
epicsShareFunc EpicsAtomicPtrT epicsLockedGetPtrT ( const unsigned * pTarget );
|
||||
epicsShareFunc unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget,
|
||||
unsigned oldval, unsigned newval );
|
||||
epicsShareFunc EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal );
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAtomic.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsMutex.h"
|
||||
|
||||
namespace {
|
||||
@@ -33,23 +34,47 @@ public:
|
||||
AtomicGuard ();
|
||||
~AtomicGuard ();
|
||||
private:
|
||||
static epicsMutexOSD & m_mutex;
|
||||
static epicsMutexOSD * m_pMutex;
|
||||
static epicsThreadOnceId m_onceFlag;
|
||||
static void m_once ( void * );
|
||||
};
|
||||
|
||||
//
|
||||
// see c++ FAQ, static init order fiasco
|
||||
// c++ 0x specifies the behavior for concurrent
|
||||
// access to block scope statics but some compiler
|
||||
// writers, lacking clear guidance in the earlier
|
||||
// c++ standards, curiously implement thread unsafe
|
||||
// block static variables despite ensuring for
|
||||
// proper multithreaded behavior for many other
|
||||
// parst of the compiler infrastructure such as
|
||||
// runtime support for exception handling
|
||||
//
|
||||
epicsMutexOSD & AtomicGuard :: m_mutex = * epicsMutexOsdCreate ();
|
||||
// since this is potentially used by the implementation
|
||||
// of staticInstance we cant use it here and must use
|
||||
// epicsThreadOnce despite its perfomance pentalty
|
||||
//
|
||||
// using epicsThreadOnce here (at this time) increases
|
||||
// the overhead of AtomicGuard by as much as 100%
|
||||
//
|
||||
epicsMutexOSD * AtomicGuard :: m_pMutex = 0;
|
||||
epicsThreadOnceId AtomicGuard :: m_onceFlag = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
void AtomicGuard :: m_once ( void * )
|
||||
{
|
||||
m_pMutex = epicsMutexOsdCreate ();
|
||||
}
|
||||
|
||||
inline AtomicGuard :: AtomicGuard ()
|
||||
{
|
||||
const int status = epicsMutexOsdLock ( & m_mutex );
|
||||
|
||||
epicsThreadOnce ( & m_onceFlag, m_once, 0 );
|
||||
const int status = epicsMutexOsdLock ( m_pMutex );
|
||||
assert ( status == epicsMutexLockOK );
|
||||
}
|
||||
|
||||
inline AtomicGuard :: ~AtomicGuard ()
|
||||
{
|
||||
epicsMutexOsdUnlock ( & m_mutex );
|
||||
epicsMutexOsdUnlock ( m_pMutex );
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
@@ -92,14 +117,26 @@ unsigned epicsLockedGetUIntT ( const unsigned * pTarget )
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget )
|
||||
unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget,
|
||||
unsigned oldval, unsigned newval )
|
||||
{
|
||||
AtomicGuard atomicGuard;
|
||||
const bool weWillSetIt = ( *pTarget == 0u );
|
||||
if ( weWillSetIt ) {
|
||||
*pTarget = 1u;
|
||||
const unsigned cur = *pTarget;
|
||||
if ( cur == oldval ) {
|
||||
*pTarget = newval;
|
||||
}
|
||||
return weWillSetIt;
|
||||
return cur;
|
||||
}
|
||||
|
||||
EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval )
|
||||
{
|
||||
AtomicGuard atomicGuard;
|
||||
const EpicsAtomicPtrT cur = *pTarget;
|
||||
if ( cur == oldval ) {
|
||||
*pTarget = newval;
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
} // end of extern "C"
|
||||
|
||||
@@ -22,16 +22,6 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
{
|
||||
return epicsLockedTestAndSetUIntT ( pTarget );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
|
||||
{
|
||||
epicsLockedSetUIntT ( pTarget, newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
return epicsLockedIncrSizeT ( pTarget );
|
||||
@@ -57,6 +47,33 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget )
|
||||
return epicsLockedGetUIntT ( pTarget );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
|
||||
{
|
||||
epicsLockedSetUIntT ( pTarget, newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
epicsLockedSetPtrT ( pTarget, newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget )
|
||||
{
|
||||
return epicsLockedGetPtrT ( pTarget );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAomicCmpAndSwapUIntT ( unsigned * pTarget,
|
||||
unsigned oldVal, unsigned newVal )
|
||||
{
|
||||
return epicsLockedCmpAndSwapUIntT ( pTarget, oldVal, newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval )
|
||||
{
|
||||
return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
@@ -67,9 +84,12 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget )
|
||||
# define epicsAtomicDecrSizeT epicsLockedDecrSizeT
|
||||
# define epicsAtomicSetSizeT epicsLockedSetSizeT
|
||||
# define epicsAtomicSetUIntT epicsLockedSetUIntT
|
||||
# define epicsAtomicSetPtrT epicsLockedSetPtrT
|
||||
# define epicsAtomicGetSizeT epicsLockedGetSizeT
|
||||
# define epicsAtomicGetUIntT epicsLockedGetUIntT
|
||||
# define epicsAtomicTestAndSetUIntT epicsLockedTestAndSetUIntT
|
||||
# define epicsAtomicGetPtrT epicsLockedGetPtrT
|
||||
# define epicsAtomicCmpAndSwapUIntT epicsLockedCmpAndSwapUIntT
|
||||
# define epicsAtomicCmpAndSwapPtrT epicsLockedCmpAndSwapPtrT
|
||||
|
||||
#endif /* if defined ( OSD_ATOMIC_INLINE ) */
|
||||
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */
|
||||
#include <stdint.h>
|
||||
|
||||
#include "epicsAssert.h"
|
||||
|
||||
#define STRICT
|
||||
@@ -33,37 +30,70 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* 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__
|
||||
|
||||
/* necessary for next three functions */
|
||||
STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) );
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
|
||||
{
|
||||
LONG * const pTarg = ( LONG * ) ( pTarget );
|
||||
InterlockedExchange ( pTarg, ( LONG ) newVal );
|
||||
*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 )
|
||||
{
|
||||
LONG * const pTarg = ( LONG * ) ( pTarget );
|
||||
return InterlockedExchangeAdd ( pTarg, 0 );
|
||||
MemoryBarrier ();
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
long * const pTarg = ( LONG * ) ( pTarget );
|
||||
return InterlockedCompareExchange ( pTarg, 1, 0 ) == 0;
|
||||
MemoryBarrier ();
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
/*
|
||||
* on win32 a LONG is 32 bits, but I am concerned that
|
||||
* we shouldnt use LONG_MAX here because with certain
|
||||
* compilers a long will be 64 bits wide
|
||||
*/
|
||||
#define WIN32_LONG_MAX 0xffffffff
|
||||
#if SIZE_MAX == WIN32_LONG_MAX
|
||||
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 four functions
|
||||
* 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
|
||||
@@ -82,22 +112,18 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
return InterlockedDecrement ( pTarg );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
LONG * const pTarg = ( LONG * ) ( pTarget );
|
||||
InterlockedExchange ( pTarg, ( LONG ) newVal );
|
||||
return (EpicsAtomicPtrT) InterlockedCompareExchange ( pTarg,
|
||||
(LONG) newVal, (LONG) oldVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
LONG * const pTarg = ( LONG * ) ( pTarget );
|
||||
return InterlockedExchangeAdd ( pTarg, 0 );
|
||||
}
|
||||
|
||||
#else /* SIZE_MAX == WIN32_LONG_MAX */
|
||||
#elif defined ( _WIN64 )
|
||||
|
||||
/*
|
||||
* necessary for next four functions
|
||||
* necessary for next five functions
|
||||
*/
|
||||
STATIC_ASSERT ( sizeof ( LONGLONG ) == sizeof ( size_t ) );
|
||||
|
||||
@@ -113,19 +139,15 @@ OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
return InterlockedDecrement64 ( pTarg );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget );
|
||||
InterlockedExchange64 ( pTarg, ( LONGLONG ) newVal );
|
||||
return (EpicsAtomicPtrT) InterlockedCompareExchange64 ( pTarg,
|
||||
(LONGLONG) newVal, (LONGLONG) oldVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget );
|
||||
return InterlockedExchangeAdd64 ( pTarg, 0 );
|
||||
}
|
||||
|
||||
#endif /* SIZE_MAX == WIN32_LONG_MAX */
|
||||
#endif /* if defined ( _WIN32 ) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
|
||||
@@ -33,91 +33,66 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget,
|
||||
unsigned oldVal, unsigned newVal )
|
||||
{
|
||||
const uint_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u );
|
||||
return oldVal == 0u;
|
||||
return atomic_cas_uint ( pTarget, oldVal, newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
return atomic_cas_ptr ( pTarget, oldVal, newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
void * const pTarg = ( void * ) ( pTarget );
|
||||
return ( size_t ) atomic_inc_ptr_nv ( pTarg );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
{
|
||||
void * const pTarg = ( void * ) ( pTarget );
|
||||
return atomic_dec_ptr_nv ( pTarg );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
|
||||
{
|
||||
atomic_swap_uint ( pTarget, newVal );
|
||||
*pTarget = newVal;
|
||||
membar_producer();
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
{
|
||||
*pTarget = newVal;
|
||||
membar_producer();
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
*pTarget = newVal;
|
||||
membar_producer();
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget )
|
||||
{
|
||||
/*
|
||||
* we cast away const, but are careful not to modify
|
||||
* the target
|
||||
*/
|
||||
unsigned * const pTarg = ( unsigned * ) ( pTarget );
|
||||
return atomic_or_uint_nv ( pTarg, 0U );
|
||||
}
|
||||
|
||||
#if SIZE_MAX == UINT_MAX
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
unsigned * const pTarg = ( unsigned * ) ( pTarget );
|
||||
return atomic_inc_uint_nv ( pTarg );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
{
|
||||
unsigned * const pTarg = ( unsigned * ) ( pTarget );
|
||||
return atomic_dec_uint_nv ( pTarg );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
{
|
||||
unsigned * const pTarg = ( unsigned * ) ( pTarget );
|
||||
atomic_swap_uint ( pTarg, newVal );
|
||||
membar_consumer ();
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
/*
|
||||
* we cast away const, but are careful not to modify
|
||||
* the target
|
||||
*/
|
||||
unsigned * const pTarg = ( unsigned * ) ( pTarget );
|
||||
return atomic_or_uint_nv ( pTarg, 0U );
|
||||
membar_consumer ();
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
#elif SIZE_MAX == ULONG_MAX
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget )
|
||||
{
|
||||
unsigned long * const pTarg = ( unsigned long * ) ( pTarget );
|
||||
return atomic_inc_ulong_nv ( pTarg );
|
||||
membar_consumer ();
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
{
|
||||
unsigned long * const pTarg = ( unsigned long * ) ( pTarget );
|
||||
return atomic_dec_ulong_nv ( pTarg );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
{
|
||||
unsigned long * const pTarg = ( unsigned long * ) ( pTarget );
|
||||
atomic_swap_ulong ( pTarg, newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
/*
|
||||
* we cast away const, but are careful not to modify
|
||||
* the target
|
||||
*/
|
||||
unsigned long * const pTarg = ( unsigned long * ) ( pTarget );
|
||||
return atomic_or_ulong_nv ( pTarg, 0UL );
|
||||
}
|
||||
|
||||
#else
|
||||
# error unsupported solaris architecture
|
||||
#endif /* SIZE_MAX == UINT_MAX */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -75,13 +75,32 @@ OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
vxAtomicSet ( pTarg, newVal );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
#else /* SIZE_MAX == UINT_MAX */
|
||||
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,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
|
||||
return (EpicsAtomicPtrT) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
|
||||
}
|
||||
|
||||
#else /* ULONG_MAX == UINT_MAX */
|
||||
|
||||
/*
|
||||
* if its 64 bit vxWorks and the compiler doesnt
|
||||
@@ -104,12 +123,28 @@ 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 );
|
||||
}
|
||||
|
||||
#endif /* SIZE_MAX == UINT_MAX */
|
||||
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 ) );
|
||||
|
||||
@@ -119,13 +154,6 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal
|
||||
vxAtomicSet ( pTarg, newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
{
|
||||
STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) );
|
||||
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
|
||||
return vxCas ( pTarg, 0, 1 ) != 0;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget )
|
||||
{
|
||||
STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) );
|
||||
@@ -133,6 +161,13 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget )
|
||||
return ( unsigned ) vxAtomicGet ( pTarg );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget,
|
||||
unsigned oldVal, unsigned newVal )
|
||||
{
|
||||
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
|
||||
return (unsigned) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
@@ -196,6 +231,15 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal
|
||||
*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 )
|
||||
{
|
||||
/*
|
||||
@@ -214,10 +258,51 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget )
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget )
|
||||
{
|
||||
STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) );
|
||||
return vxTas ( 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;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -305,46 +305,46 @@ inline void oneThousandAtomicIncr ( size_t & target )
|
||||
oneHundredAtomicIncr ( target );
|
||||
}
|
||||
|
||||
inline void tenAtomicTestAndSet ( unsigned & target )
|
||||
inline void tenAtomicCmpAndSwap ( unsigned & target )
|
||||
{
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
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 );
|
||||
}
|
||||
|
||||
inline void oneHundredAtomicTestAndSet ( unsigned & target )
|
||||
inline void oneHundredAtomicCmpAndSwap ( unsigned & target )
|
||||
{
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicCmpAndSwap ( target );
|
||||
tenAtomicCmpAndSwap ( target );
|
||||
tenAtomicCmpAndSwap ( target );
|
||||
tenAtomicCmpAndSwap ( target );
|
||||
tenAtomicCmpAndSwap ( target );
|
||||
tenAtomicCmpAndSwap ( target );
|
||||
tenAtomicCmpAndSwap ( target );
|
||||
tenAtomicCmpAndSwap ( target );
|
||||
tenAtomicCmpAndSwap ( target );
|
||||
tenAtomicCmpAndSwap ( target );
|
||||
}
|
||||
|
||||
inline void oneThousandAtomicTestAndSet ( unsigned & target )
|
||||
inline void oneThousandAtomicCmpAndSwap ( unsigned & target )
|
||||
{
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( 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 )
|
||||
@@ -421,20 +421,20 @@ void epicsAtomicIncrPerformance ()
|
||||
testDiag ( "epicsAtomicIncr() takes %f microseconds", delay );
|
||||
}
|
||||
|
||||
void atomicTestAndSetPerformance ()
|
||||
void atomicCmpAndSwapPerformance ()
|
||||
{
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
unsigned target;
|
||||
epicsAtomicSetUIntT ( & target, 0 );
|
||||
testOk1 ( ! target );
|
||||
for ( unsigned i = 0; i < N; i++ ) {
|
||||
oneThousandAtomicTestAndSet ( target );
|
||||
oneThousandAtomicCmpAndSwap ( target );
|
||||
}
|
||||
double delay = epicsTime::getCurrent () - begin;
|
||||
testOk1 ( target );
|
||||
delay /= N * 1000u; // convert to delay per call
|
||||
delay *= 1e6; // convert to micro seconds
|
||||
testDiag ( "epicsAtomicCompareAndSet() takes %f microseconds", delay );
|
||||
testDiag ( "epicsAtomicCmpAndSwap() takes %f microseconds", delay );
|
||||
}
|
||||
|
||||
void recursiveOwnershipRetPerformance ()
|
||||
@@ -494,6 +494,6 @@ MAIN(epicsAtomicPerform)
|
||||
epicsAtomicIncrPerformance ();
|
||||
recursiveOwnershipRetPerformance ();
|
||||
ownershipPassRefPerformance ();
|
||||
atomicCompareAndSetPerformance ();
|
||||
atomicCmpAndSwapPerformance ();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
@@ -27,94 +27,147 @@ static void decr ( void *arg )
|
||||
epicsAtomicIncrSizeT ( & pTestData->m_testIterations );
|
||||
}
|
||||
|
||||
typedef struct TestDataTNS {
|
||||
typedef struct TestDataTNS_UIntT {
|
||||
unsigned m_testValue;
|
||||
size_t m_testIterationsSet;
|
||||
size_t m_testIterationsNotSet;
|
||||
} TestDataTNS;
|
||||
} 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 ( void *arg )
|
||||
static void tns_UIntT ( void *arg )
|
||||
{
|
||||
TestDataTNS * const pTestData = (TestDataTNS *) arg;
|
||||
TestDataTNS_UIntT * const pTestData = (TestDataTNS_UIntT *) arg;
|
||||
/*
|
||||
* intentionally waste cpu and maximize
|
||||
* contention for the shared data
|
||||
*/
|
||||
epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet );
|
||||
while ( ! epicsAtomicTestAndSetUIntT ( & pTestData->m_testValue ) ) {
|
||||
while ( ! epicsAtomicCmpAndSwapUIntT ( & pTestData->m_testValue, 0u, 1u ) ) {
|
||||
}
|
||||
testOk ( epicsAtomicGetUIntT ( & pTestData->m_testValue ),
|
||||
"test and set must leave operand in true state" );
|
||||
epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet );
|
||||
epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u );
|
||||
epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet );
|
||||
}
|
||||
|
||||
MAIN(epicsAtomicTest)
|
||||
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 );
|
||||
|
||||
static const size_t N_incrDecr = 100;
|
||||
static const size_t N_testAndSet = 10;
|
||||
|
||||
testPlan( 9 + N_testAndSet );
|
||||
testPlan(14);
|
||||
|
||||
{
|
||||
|
||||
static const size_t N = 100;
|
||||
size_t i;
|
||||
TestDataIncrDecr testData = { 0, N_incrDecr };
|
||||
epicsAtomicSetSizeT ( & testData.m_testValue, N_incrDecr );
|
||||
testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr,
|
||||
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_incrDecr; i++ ) {
|
||||
epicsThreadCreate ( "incr", 50, stackSize, incr, & testData );
|
||||
epicsThreadCreate ( "decr", 50, stackSize, decr, & testData );
|
||||
for ( i = 0u; i < N; i++ ) {
|
||||
epicsThreadCreate ( "incr",
|
||||
50, stackSize, incr, & testData );
|
||||
epicsThreadCreate ( "decr",
|
||||
50, stackSize, decr, & testData );
|
||||
}
|
||||
while ( testData.m_testIterations < 2 * N_incrDecr ) {
|
||||
while ( testData.m_testIterations < 2 * N ) {
|
||||
epicsThreadSleep ( 0.01 );
|
||||
}
|
||||
testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N_incrDecr,
|
||||
"incr/decr iterations %u", testData.m_testIterations );
|
||||
testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr,
|
||||
"incr/decr final value %u", testData.m_testValue );
|
||||
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 testData = { 1, N_testAndSet, N_testAndSet };
|
||||
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 );
|
||||
for ( i = 0u; i < N_testAndSet; i++ ) {
|
||||
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, & testData );
|
||||
50, stackSize, tns_UIntT, & testData );
|
||||
}
|
||||
epicsAtomicSetUIntT ( & testData.m_testValue, 0u );
|
||||
while ( testData.m_testIterationsSet < N_testAndSet ) {
|
||||
while ( testData.m_testIterationsSet < N ) {
|
||||
epicsThreadSleep ( 0.01 );
|
||||
}
|
||||
testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N_testAndSet,
|
||||
"test and set iterations %u", testData.m_testIterationsSet );
|
||||
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 );
|
||||
"test and set not-set tracking = %u",
|
||||
testData.m_testIterationsNotSet );
|
||||
}
|
||||
|
||||
{
|
||||
static unsigned setVal = 5;
|
||||
epicsAtomicSetUIntT ( & testData.m_testValue, setVal );
|
||||
testOk ( epicsAtomicGetUIntT ( & testData.m_testValue ) == setVal,
|
||||
"unsigned version of set and get must concur" );
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user