o added epicsAtomic implementation including compiler and os specific files
o added functionality and performance testing
This commit is contained in:
committed by
Andrew Johnson
parent
fa55316272
commit
747a59fd7f
@@ -0,0 +1,27 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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 cdAtomic_h
|
||||
#define cdAtomic_h
|
||||
|
||||
#if defined ( __cplusplus )
|
||||
# define OSD_ATOMIC_INLINE inline
|
||||
#else
|
||||
# define OSD_ATOMIC_INLINE __inline__
|
||||
#endif
|
||||
|
||||
#include "osdAtomic.h"
|
||||
|
||||
#endif /* cdAtomic_h */
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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 cdAtomic_h
|
||||
#define cdAtomic_h
|
||||
|
||||
#if __STDC_VERSION__ >= 199901L || defined ( __cplusplus )
|
||||
# define OSD_ATOMIC_INLINE inline
|
||||
#endif
|
||||
|
||||
#include "osdAtomic.h"
|
||||
|
||||
#endif /* cdAtomic_h */
|
||||
@@ -0,0 +1,97 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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 cdAtomic_h
|
||||
#define cdAtomic_h
|
||||
|
||||
#ifndef __GNUC__
|
||||
# error this header is only for use with the gnu compiler
|
||||
#endif
|
||||
|
||||
#define OSD_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 \
|
||||
GCC_ATOMIC_CONCAT ( \
|
||||
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
|
||||
__SIZEOF_INT__ )
|
||||
|
||||
#define GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
|
||||
GCC_ATOMIC_CONCAT ( \
|
||||
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
|
||||
__SIZEOF_SIZE_T__ )
|
||||
|
||||
#if GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \
|
||||
&& defined GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T
|
||||
|
||||
#define OSD_ATOMIC_GCC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
return __sync_add_and_fetch ( pTarget, 1u );
|
||||
}
|
||||
|
||||
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 size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
__sync_synchronize ();
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
{
|
||||
const size_t prev = __sync_lock_test_and_set ( pTarget, 1u );
|
||||
return prev == 0;
|
||||
}
|
||||
|
||||
#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 "osdAtomic.h"
|
||||
|
||||
#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL */
|
||||
|
||||
#endif /* cdAtomic_h */
|
||||
@@ -0,0 +1,165 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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 cdAtomic_h
|
||||
#define cdAtomic_h
|
||||
|
||||
#include "epicsAssert.h"
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# error this header file is only for use with with the Microsoft Compiler
|
||||
#endif
|
||||
|
||||
#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 )
|
||||
#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
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* necessary for next two 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 );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
{
|
||||
long * const pTarg = ( long * ) ( pTarget );
|
||||
return _InterlockedCompareExchange ( pTarg, 1, 0 ) == 0;
|
||||
}
|
||||
|
||||
|
||||
#if ! OSD_ATOMIC_64
|
||||
|
||||
/*
|
||||
* necessary for next four 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 void epicsAtomicSetSizeT ( size_t * pTarget, size_t 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 );
|
||||
}
|
||||
|
||||
#else /* ! OSD_ATOMIC_64 */
|
||||
|
||||
/*
|
||||
* necessary for next four 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 void epicsAtomicSetSizeT ( size_t * pTarget, size_t 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 );
|
||||
}
|
||||
|
||||
#endif /* ! OSD_ATOMIC_64 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#else /* ifdef _MSC_EXTENSIONS */
|
||||
|
||||
#if defined ( __cplusplus )
|
||||
# define OSD_ATOMIC_INLINE inline
|
||||
# include "osdAtomic.h"
|
||||
#endif
|
||||
|
||||
#endif /* ifdef _MSC_EXTENSIONS */
|
||||
|
||||
#endif /* cdAtomic_h */
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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 cdAtomic_h
|
||||
#define cdAtomic_h
|
||||
|
||||
#if defined ( __cplusplus )
|
||||
# define OSD_ATOMIC_INLINE inline
|
||||
#else
|
||||
# define OSD_ATOMIC_INLINE __inline
|
||||
#endif
|
||||
|
||||
#include "osdAtomic.h"
|
||||
|
||||
#endif /* cdAtomic_h */
|
||||
@@ -0,0 +1,99 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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 epicsAtomic_h
|
||||
#define epicsAtomic_h
|
||||
|
||||
#include <stdlib.h> /* define size_t */
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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,
|
||||
* 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 );
|
||||
|
||||
/*
|
||||
* 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,
|
||||
* 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 );
|
||||
|
||||
/*
|
||||
* set target in cache, flush target in cache
|
||||
*/
|
||||
epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue );
|
||||
epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue );
|
||||
|
||||
/*
|
||||
* fetch target in cache, return new value of target
|
||||
*/
|
||||
epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * 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
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
epicsShareFunc unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget );
|
||||
|
||||
/*
|
||||
* the following are, never inline and always synchronized by a global
|
||||
* mutual exclusion lock, implementations of the epicsAtomicXxxx interface
|
||||
* which may used to implement the epicsAtomicXxxx functions when
|
||||
* more efficent primitives aren't available
|
||||
*/
|
||||
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 size_t epicsLockedGetSizeT ( const size_t * pTarget );
|
||||
epicsShareFunc unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget );
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* options for inline compiler instrinsic or os specific
|
||||
* implementations of the above function prototypes
|
||||
*/
|
||||
#include "epicsAtomicCD.h"
|
||||
|
||||
#endif /* epicsAtomic_h */
|
||||
@@ -0,0 +1,103 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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
|
||||
*
|
||||
* Provide a global mutex version of the atomic functions for when
|
||||
* we dont have more efficent OS primitives or compiler intriniscs
|
||||
* to use instead.
|
||||
*
|
||||
* We implement these mutex-based primitives upon the libCom private
|
||||
* interface epicsMutexOsdXxxx because, in libCom, it is convenient
|
||||
* to make this a standalone primitive upon which we can implement
|
||||
* epicsMutex.
|
||||
*/
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAtomic.h"
|
||||
#include "epicsMutex.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class AtomicGuard {
|
||||
public:
|
||||
AtomicGuard ();
|
||||
~AtomicGuard ();
|
||||
private:
|
||||
static epicsMutexOSD & m_mutex;
|
||||
};
|
||||
|
||||
//
|
||||
// see c++ FAQ, static init order fiasco
|
||||
//
|
||||
epicsMutexOSD & AtomicGuard :: m_mutex = * epicsMutexOsdCreate ();
|
||||
|
||||
inline AtomicGuard :: AtomicGuard ()
|
||||
{
|
||||
const int status = epicsMutexOsdLock ( & m_mutex );
|
||||
assert ( status == epicsMutexLockOK );
|
||||
}
|
||||
|
||||
inline AtomicGuard :: ~AtomicGuard ()
|
||||
{
|
||||
epicsMutexOsdUnlock ( & m_mutex );
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
size_t epicsLockedIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
AtomicGuard atomicGuard;
|
||||
return ++(*pTarget);
|
||||
}
|
||||
|
||||
size_t epicsLockedDecrSizeT ( size_t * pTarget )
|
||||
{
|
||||
AtomicGuard atomicGuard;
|
||||
return --(*pTarget);
|
||||
}
|
||||
|
||||
void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
{
|
||||
AtomicGuard atomicGuard;
|
||||
*pTarget = newVal;
|
||||
}
|
||||
|
||||
void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal )
|
||||
{
|
||||
AtomicGuard atomicGuard;
|
||||
*pTarget = newVal;
|
||||
}
|
||||
|
||||
size_t epicsLockedGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
AtomicGuard atomicGuard;
|
||||
return *pTarget;
|
||||
}
|
||||
|
||||
unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget )
|
||||
{
|
||||
AtomicGuard atomicGuard;
|
||||
const bool weWillSetIt = ( *pTarget == 0u );
|
||||
if ( weWillSetIt ) {
|
||||
*pTarget = 1u;
|
||||
}
|
||||
return weWillSetIt;
|
||||
}
|
||||
|
||||
} // end of extern "C"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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 epicsAtomicLocked_h
|
||||
#define epicsAtomicLocked_h
|
||||
|
||||
#if defined ( OSD_ATOMIC_INLINE )
|
||||
|
||||
#ifdef __cplusplus
|
||||
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 );
|
||||
}
|
||||
|
||||
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 size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
return epicsLockedGetSizeT ( pTarget );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#else /* if defined ( OSD_ATOMIC_INLINE ) */
|
||||
|
||||
# define epicsAtomicIncrSizeT epicsLockedIncrSizeT
|
||||
# define epicsAtomicDecrSizeT epicsLockedDecrSizeT
|
||||
# define epicsAtomicSetSizeT epicsLockedSetSizeT
|
||||
# define epicsAtomicSetUIntT epicsLockedSetUIntT
|
||||
# define epicsAtomicGetSizeT epicsLockedGetSizeT
|
||||
# define epicsAtomicTestAndSetUIntT epicsLockedTestAndSetUIntT
|
||||
|
||||
#endif /* if defined ( OSD_ATOMIC_INLINE ) */
|
||||
|
||||
#endif /* epicsAtomicLocked_h */
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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 osdAtomic_h
|
||||
#define osdAtomic_h
|
||||
|
||||
#if defined ( OSD_ATOMIC_INLINE )
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */
|
||||
#include <stdint.h>
|
||||
|
||||
#include "epicsAssert.h"
|
||||
|
||||
#define STRICT
|
||||
#define VC_EXTRALEAN
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* necessary for next two 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 );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
{
|
||||
long * const pTarg = ( LONG * ) ( pTarget );
|
||||
return InterlockedCompareExchange ( pTarg, 1, 0 ) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
/*
|
||||
* necessary for next four 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 void epicsAtomicSetSizeT ( size_t * pTarget, size_t 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 );
|
||||
}
|
||||
|
||||
#else /* SIZE_MAX == WIN32_LONG_MAX */
|
||||
|
||||
/*
|
||||
* necessary for next four 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 void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
{
|
||||
LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget );
|
||||
InterlockedExchange64 ( pTarg, ( LONGLONG ) newVal );
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* if defined ( OSD_ATOMIC_INLINE ) */
|
||||
|
||||
#endif /* ifndef osdAtomic_h */
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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 osdAtomic
|
||||
#define osdAtomic
|
||||
|
||||
#include "epicsAtomicLocked.h"
|
||||
|
||||
#endif /* osdAtomic */
|
||||
@@ -0,0 +1,105 @@
|
||||
|
||||
/*************************************************************************\
|
||||
* 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 osdAtomic_h
|
||||
#define osdAtomic_h
|
||||
|
||||
#if defined ( OSD_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>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
{
|
||||
const uchar_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u );
|
||||
return oldVal == 0u;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
|
||||
{
|
||||
atomic_swap_uint ( pTarget, newVal );
|
||||
}
|
||||
|
||||
#if SIZE_MAX == UINT_MAX
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
return atomic_inc_uint_nv ( pTarget );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
{
|
||||
return atomic_dec_uint_nv ( pTarget );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
{
|
||||
atomic_swap_uint ( pTarget, newVal );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
return atomic_or_uint_nv ( pTarget, 0U );
|
||||
}
|
||||
|
||||
#else /* SIZE_MAX == UINT_MAX */
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
return atomic_inc_ulong_nv ( pTarget );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
{
|
||||
return atomic_dec_ulong_nv ( pTarget );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
|
||||
{
|
||||
atomic_swap_ulong ( pTarget, newval );
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
return atomic_or_ulong_nv ( pTarget, 0U );
|
||||
}
|
||||
|
||||
#endif /* SIZE_MAX == UINT_MAX */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#else /* ifdef __SunOS_5_10 */
|
||||
|
||||
#include "epicsAtomicLocked.h"
|
||||
|
||||
#endif /* ifdef __SunOS_5_10 */
|
||||
|
||||
#endif /* if defined ( OSD_ATOMIC_INLINE ) */
|
||||
|
||||
#endif /* osdAtomic_h */
|
||||
@@ -0,0 +1,211 @@
|
||||
/*************************************************************************\
|
||||
* 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 osdAtomic_h
|
||||
#define osdAtomic_h
|
||||
|
||||
#if defined ( OSD_ATOMIC_INLINE )
|
||||
|
||||
#include "vxWorks.h" /* obtain the version of vxWorks */
|
||||
|
||||
/*
|
||||
* With vxWorks 6.6 and later we need to use vxAtomicLib
|
||||
* to implement this functionality correctly on SMP systems
|
||||
*/
|
||||
#if _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606
|
||||
|
||||
#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <vxAtomicLib.h>
|
||||
#include "epicsAssert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* we make the probably correct guess that if SIZE_MAX
|
||||
* is the same as UINT_MAX then sizeof ( atomic_t )
|
||||
* will be the same as sizeof ( size_t )
|
||||
*
|
||||
* if SIZE_MAX != UINT_MAX then its 64 bit vxWorks and
|
||||
* WRS doesnt not supply at this time the atomic interface
|
||||
* for 8 byte integers that is needed - so that architecture
|
||||
* receives the lock synchronized version
|
||||
*/
|
||||
#if SIZE_MAX == UINT_MAX
|
||||
|
||||
STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) );
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
/*
|
||||
* vxAtomicLib doc indicates that vxAtomicInc is
|
||||
* implemented using unsigned arithmetic
|
||||
*/
|
||||
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 )
|
||||
{
|
||||
/*
|
||||
* vxAtomicLib doc indicates that vxAtomicDec is
|
||||
* implemented using unsigned arithmetic
|
||||
*/
|
||||
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
|
||||
const atomic_t oldVal = vxAtomicDec ( pTarg ) - 1;
|
||||
return ( ( size_t ) ( oldVal ) ) - 1u;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t 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 */
|
||||
|
||||
/*
|
||||
* if its 64 bit 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
|
||||
*/
|
||||
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 size_t epicsAtomicGetSizeT ( const size_t * pTarget )
|
||||
{
|
||||
return epicsLockedGetSizeT ( pTarget );
|
||||
}
|
||||
|
||||
#endif /* SIZE_MAX == UINT_MAX */
|
||||
|
||||
STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) );
|
||||
|
||||
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
|
||||
{
|
||||
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
|
||||
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 ( pTarget, 0, 1 ) != 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#else /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
|
||||
|
||||
#include "intLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
{
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 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 epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
|
||||
{
|
||||
STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) );
|
||||
int * const pTarg = ( int * ) ( pTarget );
|
||||
const BOOL weSetIt = vxTas ( pTarg, 0, 1 );
|
||||
return weSetIt != 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
|
||||
|
||||
#endif /* if defined ( OSD_ATOMIC_INLINE ) */
|
||||
|
||||
#endif /* osdAtomic_h */
|
||||
@@ -0,0 +1,499 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#include "epicsInterrupt.h"
|
||||
#include "epicsAtomic.h"
|
||||
#include "epicsTime.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
|
||||
using std :: size_t;
|
||||
|
||||
class RefCtr {
|
||||
public:
|
||||
RefCtr ();
|
||||
~RefCtr ();
|
||||
void reference ();
|
||||
void unreference ();
|
||||
private:
|
||||
size_t m_cnt;
|
||||
};
|
||||
|
||||
class Ownership {
|
||||
public:
|
||||
Ownership ();
|
||||
Ownership ( RefCtr & refCtr );
|
||||
Ownership ( const Ownership & );
|
||||
~Ownership ();
|
||||
Ownership & operator = ( const Ownership & );
|
||||
private:
|
||||
RefCtr * _pRefCtr;
|
||||
static RefCtr m_noOwnership;
|
||||
};
|
||||
|
||||
inline RefCtr :: RefCtr ()
|
||||
{
|
||||
epicsAtomicSetSizeT ( & m_cnt, 0 );
|
||||
}
|
||||
|
||||
inline RefCtr :: ~RefCtr ()
|
||||
{
|
||||
unsigned cnt = epicsAtomicGetSizeT ( & m_cnt );
|
||||
assert ( cnt == 0u );
|
||||
}
|
||||
|
||||
inline void RefCtr :: reference ()
|
||||
{
|
||||
epicsAtomicIncrSizeT ( & m_cnt );
|
||||
}
|
||||
|
||||
inline void RefCtr :: unreference ()
|
||||
{
|
||||
epicsAtomicDecrSizeT ( & m_cnt );
|
||||
}
|
||||
|
||||
RefCtr Ownership :: m_noOwnership;
|
||||
|
||||
inline Ownership :: Ownership () :
|
||||
_pRefCtr ( & m_noOwnership )
|
||||
{
|
||||
m_noOwnership.reference ();
|
||||
}
|
||||
|
||||
inline Ownership :: Ownership ( RefCtr & refCtr ) :
|
||||
_pRefCtr ( & refCtr )
|
||||
{
|
||||
refCtr.reference ();
|
||||
}
|
||||
|
||||
inline Ownership :: Ownership ( const Ownership & ownership ) :
|
||||
_pRefCtr ( ownership._pRefCtr )
|
||||
{
|
||||
_pRefCtr->reference ();
|
||||
}
|
||||
|
||||
inline Ownership :: ~Ownership ()
|
||||
{
|
||||
_pRefCtr->unreference ();
|
||||
}
|
||||
|
||||
inline Ownership & Ownership ::
|
||||
operator = ( const Ownership & ownership )
|
||||
{
|
||||
RefCtr * const pOldRefCtr = _pRefCtr;
|
||||
_pRefCtr = ownership._pRefCtr;
|
||||
_pRefCtr->reference ();
|
||||
pOldRefCtr->unreference ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Ownership retOwnership ( const Ownership & ownership )
|
||||
{
|
||||
return Ownership ( ownership );
|
||||
}
|
||||
|
||||
inline Ownership recurRetOwner10 ( const Ownership & ownershipIn )
|
||||
{
|
||||
Ownership ownership =
|
||||
retOwnership (
|
||||
retOwnership (
|
||||
retOwnership (
|
||||
retOwnership (
|
||||
retOwnership ( ownershipIn ) ) ) ) );
|
||||
return retOwnership (
|
||||
retOwnership (
|
||||
retOwnership (
|
||||
retOwnership (
|
||||
retOwnership ( ownership ) ) ) ) );
|
||||
}
|
||||
|
||||
inline Ownership recurRetOwner100 ( const Ownership & ownershipIn )
|
||||
{
|
||||
Ownership ownership =
|
||||
recurRetOwner10 (
|
||||
recurRetOwner10 (
|
||||
recurRetOwner10 (
|
||||
recurRetOwner10 (
|
||||
recurRetOwner10 ( ownershipIn ) ) ) ) );
|
||||
return recurRetOwner10 (
|
||||
recurRetOwner10 (
|
||||
recurRetOwner10 (
|
||||
recurRetOwner10 (
|
||||
recurRetOwner10 ( ownership ) ) ) ) );
|
||||
}
|
||||
|
||||
inline Ownership recurRetOwner1000 ( const Ownership & ownershipIn )
|
||||
{
|
||||
Ownership ownership =
|
||||
recurRetOwner100 (
|
||||
recurRetOwner100 (
|
||||
recurRetOwner100 (
|
||||
recurRetOwner100 (
|
||||
recurRetOwner100 ( ownershipIn ) ) ) ) );
|
||||
return recurRetOwner100 (
|
||||
recurRetOwner100 (
|
||||
recurRetOwner100 (
|
||||
recurRetOwner100 (
|
||||
recurRetOwner100 ( ownership ) ) ) ) );
|
||||
}
|
||||
|
||||
inline void passRefOwnership ( const Ownership & ownershipIn, Ownership & ownershipOut )
|
||||
{
|
||||
ownershipOut = ownershipIn;
|
||||
}
|
||||
|
||||
inline void passRefOwnership10 ( const Ownership & ownershipIn, Ownership & ownershipOut )
|
||||
{
|
||||
Ownership ownershipTmp0;
|
||||
passRefOwnership ( ownershipIn, ownershipTmp0 );
|
||||
Ownership ownershipTmp1;
|
||||
passRefOwnership ( ownershipTmp0, ownershipTmp1 );
|
||||
Ownership ownershipTmp2;
|
||||
passRefOwnership ( ownershipTmp1, ownershipTmp2 );
|
||||
Ownership ownershipTmp3;
|
||||
passRefOwnership ( ownershipTmp2, ownershipTmp3 );
|
||||
Ownership ownershipTmp4;
|
||||
passRefOwnership ( ownershipTmp3, ownershipTmp4 );
|
||||
Ownership ownershipTmp5;
|
||||
passRefOwnership ( ownershipTmp4, ownershipTmp5 );
|
||||
Ownership ownershipTmp6;
|
||||
passRefOwnership ( ownershipTmp5, ownershipTmp6 );
|
||||
Ownership ownershipTmp7;
|
||||
passRefOwnership ( ownershipTmp6, ownershipTmp7 );
|
||||
Ownership ownershipTmp8;
|
||||
passRefOwnership ( ownershipTmp7, ownershipTmp8 );
|
||||
passRefOwnership ( ownershipTmp8, ownershipOut );
|
||||
}
|
||||
|
||||
inline void passRefOwnership100 ( const Ownership & ownershipIn, Ownership & ownershipOut )
|
||||
{
|
||||
Ownership ownershipTmp0;
|
||||
passRefOwnership10 ( ownershipIn, ownershipTmp0 );
|
||||
Ownership ownershipTmp1;
|
||||
passRefOwnership10 ( ownershipTmp0, ownershipTmp1 );
|
||||
Ownership ownershipTmp2;
|
||||
passRefOwnership10 ( ownershipTmp1, ownershipTmp2 );
|
||||
Ownership ownershipTmp3;
|
||||
passRefOwnership10 ( ownershipTmp2, ownershipTmp3 );
|
||||
Ownership ownershipTmp4;
|
||||
passRefOwnership10 ( ownershipTmp3, ownershipTmp4 );
|
||||
Ownership ownershipTmp5;
|
||||
passRefOwnership10 ( ownershipTmp4, ownershipTmp5 );
|
||||
Ownership ownershipTmp6;
|
||||
passRefOwnership10 ( ownershipTmp5, ownershipTmp6 );
|
||||
Ownership ownershipTmp7;
|
||||
passRefOwnership10 ( ownershipTmp6, ownershipTmp7 );
|
||||
Ownership ownershipTmp8;
|
||||
passRefOwnership10 ( ownershipTmp7, ownershipTmp8 );
|
||||
passRefOwnership10 ( ownershipTmp8, ownershipOut );
|
||||
}
|
||||
|
||||
inline void passRefOwnership1000 ( const Ownership & ownershipIn, Ownership & ownershipOut )
|
||||
{
|
||||
Ownership ownershipTmp0;
|
||||
passRefOwnership100 ( ownershipIn, ownershipTmp0 );
|
||||
Ownership ownershipTmp1;
|
||||
passRefOwnership100 ( ownershipTmp0, ownershipTmp1 );
|
||||
Ownership ownershipTmp2;
|
||||
passRefOwnership100 ( ownershipTmp1, ownershipTmp2 );
|
||||
Ownership ownershipTmp3;
|
||||
passRefOwnership100 ( ownershipTmp2, ownershipTmp3 );
|
||||
Ownership ownershipTmp4;
|
||||
passRefOwnership100 ( ownershipTmp3, ownershipTmp4 );
|
||||
Ownership ownershipTmp5;
|
||||
passRefOwnership100 ( ownershipTmp4, ownershipTmp5 );
|
||||
Ownership ownershipTmp6;
|
||||
passRefOwnership100 ( ownershipTmp5, ownershipTmp6 );
|
||||
Ownership ownershipTmp7;
|
||||
passRefOwnership100 ( ownershipTmp6, ownershipTmp7 );
|
||||
Ownership ownershipTmp8;
|
||||
passRefOwnership100 ( ownershipTmp7, ownershipTmp8 );
|
||||
passRefOwnership100 ( ownershipTmp8, ownershipOut );
|
||||
}
|
||||
|
||||
time_t extTime = 0;
|
||||
|
||||
// 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 )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
inline void oneHundredOrdinaryIncr ( size_t & target )
|
||||
{
|
||||
tenOrdinaryIncr ( target );
|
||||
tenOrdinaryIncr ( target );
|
||||
tenOrdinaryIncr ( target );
|
||||
tenOrdinaryIncr ( target );
|
||||
tenOrdinaryIncr ( target );
|
||||
tenOrdinaryIncr ( target );
|
||||
tenOrdinaryIncr ( target );
|
||||
tenOrdinaryIncr ( target );
|
||||
tenOrdinaryIncr ( target );
|
||||
tenOrdinaryIncr ( target );
|
||||
}
|
||||
|
||||
inline void oneThousandOrdinaryIncr ( size_t & target )
|
||||
{
|
||||
oneHundredOrdinaryIncr ( target );
|
||||
oneHundredOrdinaryIncr ( target );
|
||||
oneHundredOrdinaryIncr ( target );
|
||||
oneHundredOrdinaryIncr ( target );
|
||||
oneHundredOrdinaryIncr ( target );
|
||||
oneHundredOrdinaryIncr ( target );
|
||||
oneHundredOrdinaryIncr ( target );
|
||||
oneHundredOrdinaryIncr ( target );
|
||||
oneHundredOrdinaryIncr ( target );
|
||||
oneHundredOrdinaryIncr ( target );
|
||||
}
|
||||
|
||||
inline void tenAtomicIncr ( size_t & target )
|
||||
{
|
||||
epicsAtomicIncrSizeT ( & target );
|
||||
epicsAtomicIncrSizeT ( & target );
|
||||
epicsAtomicIncrSizeT ( & target );
|
||||
epicsAtomicIncrSizeT ( & target );
|
||||
epicsAtomicIncrSizeT ( & target );
|
||||
epicsAtomicIncrSizeT ( & target );
|
||||
epicsAtomicIncrSizeT ( & target );
|
||||
epicsAtomicIncrSizeT ( & target );
|
||||
epicsAtomicIncrSizeT ( & target );
|
||||
epicsAtomicIncrSizeT ( & target );
|
||||
}
|
||||
|
||||
inline void oneHundredAtomicIncr ( size_t & target )
|
||||
{
|
||||
tenAtomicIncr ( target );
|
||||
tenAtomicIncr ( target );
|
||||
tenAtomicIncr ( target );
|
||||
tenAtomicIncr ( target );
|
||||
tenAtomicIncr ( target );
|
||||
tenAtomicIncr ( target );
|
||||
tenAtomicIncr ( target );
|
||||
tenAtomicIncr ( target );
|
||||
tenAtomicIncr ( target );
|
||||
tenAtomicIncr ( target );
|
||||
}
|
||||
|
||||
inline void oneThousandAtomicIncr ( size_t & target )
|
||||
{
|
||||
oneHundredAtomicIncr ( target );
|
||||
oneHundredAtomicIncr ( target );
|
||||
oneHundredAtomicIncr ( target );
|
||||
oneHundredAtomicIncr ( target );
|
||||
oneHundredAtomicIncr ( target );
|
||||
oneHundredAtomicIncr ( target );
|
||||
oneHundredAtomicIncr ( target );
|
||||
oneHundredAtomicIncr ( target );
|
||||
oneHundredAtomicIncr ( target );
|
||||
oneHundredAtomicIncr ( target );
|
||||
}
|
||||
|
||||
inline void tenAtomicTestAndSet ( unsigned & target )
|
||||
{
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
epicsAtomicTestAndSetUIntT ( & target );
|
||||
}
|
||||
|
||||
inline void oneHundredAtomicTestAndSet ( unsigned & target )
|
||||
{
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
tenAtomicTestAndSet ( target );
|
||||
}
|
||||
|
||||
inline void oneThousandAtomicTestAndSet ( unsigned & target )
|
||||
{
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( target );
|
||||
oneHundredAtomicTestAndSet ( 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 );
|
||||
}
|
||||
|
||||
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 atomicCompareAndSetPerformance ()
|
||||
{
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
size_t target;
|
||||
epicsAtomicSetSizeT ( & target, 0 );
|
||||
testOk1 ( ! target );
|
||||
for ( unsigned i = 0; i < N; i++ ) {
|
||||
oneThousandAtomicTestAndSet ( 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 );
|
||||
}
|
||||
|
||||
void recursiveOwnershipRetPerformance ()
|
||||
{
|
||||
RefCtr refCtr;
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
for ( unsigned i = 0; i < N; i++ ) {
|
||||
Ownership ownership ( refCtr );
|
||||
recurRetOwner1000 ( ownership );
|
||||
}
|
||||
double delay = epicsTime::getCurrent () - begin;
|
||||
delay /= N * 1000u; // convert to delay per call
|
||||
delay *= 1e6; // convert to micro seconds
|
||||
testDiag ( "retOwnership() takes %f microseconds", delay );
|
||||
}
|
||||
|
||||
void ownershipPassRefPerformance ()
|
||||
{
|
||||
RefCtr refCtr;
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
for ( unsigned i = 0; i < N; i++ ) {
|
||||
Ownership ownershipSrc ( refCtr );
|
||||
Ownership ownershipDest;
|
||||
passRefOwnership1000 ( ownershipSrc, ownershipDest );
|
||||
}
|
||||
double delay = epicsTime::getCurrent () - begin;
|
||||
delay /= N * 1000u; // convert to delay per call
|
||||
delay *= 1e6; // convert to micro seconds
|
||||
testDiag ( "passRefOwnership() takes %f microseconds", delay );
|
||||
}
|
||||
|
||||
void epicsAtomicSetPerformance ()
|
||||
{
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
unsigned 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 );
|
||||
}
|
||||
|
||||
MAIN(osiAtomicTest)
|
||||
{
|
||||
testPlan(5);
|
||||
//
|
||||
// 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
|
||||
//
|
||||
epicsAtomicSetPerformance ();
|
||||
ordinaryIncrPerformance ();
|
||||
epicsAtomicIncrPerformance ();
|
||||
recursiveOwnershipRetPerformance ();
|
||||
ownershipPassRefPerformance ();
|
||||
atomicCompareAndSetPerformance ();
|
||||
return testDone();
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
|
||||
#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 {
|
||||
unsigned m_testValue;
|
||||
size_t m_testIterationsSet;
|
||||
size_t m_testIterationsNotSet;
|
||||
} TestDataTNS;
|
||||
|
||||
int isModulo ( size_t N, size_t n )
|
||||
{
|
||||
return ( n % N ) == 0u;
|
||||
}
|
||||
|
||||
static void tns ( void *arg )
|
||||
{
|
||||
TestDataTNS * const pTestData = (TestDataTNS *) arg;
|
||||
/*
|
||||
* intentionally waste cpu and maximize
|
||||
* contention for the shared data
|
||||
*/
|
||||
epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet );
|
||||
while ( ! epicsAtomicTestAndSetUIntT ( & pTestData->m_testValue ) ) {
|
||||
}
|
||||
epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet );
|
||||
epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u );
|
||||
epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet );
|
||||
}
|
||||
|
||||
MAIN(osiAtomicTest)
|
||||
{
|
||||
static const size_t N = 1000;
|
||||
const unsigned int stackSize =
|
||||
epicsThreadGetStackSize ( epicsThreadStackSmall );
|
||||
|
||||
testPlan(8);
|
||||
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
{
|
||||
size_t i;
|
||||
TestDataTNS testData = { 1, 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; i++ ) {
|
||||
epicsThreadCreate ( "tns",
|
||||
50, stackSize, tns, & 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 );
|
||||
}
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user