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:
Jeff Hill
2011-08-15 17:00:01 -06:00
committed by Andrew Johnson
parent c872c44668
commit bd1b1479f4
10 changed files with 525 additions and 266 deletions

View File

@@ -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

View File

@@ -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 */

View File

@@ -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" */

View File

@@ -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"

View File

@@ -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 ) */

View File

@@ -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" */

View File

@@ -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 */

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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();